Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/pci-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/pci-2.6: (37 commits)
  PCI: merge almost all of pci_32.h and pci_64.h together
  PCI: X86: Introduce and enable PCI domain support
  PCI: Add 'nodomains' boot option, and pci_domains_supported global
  PCI: modify PCI bridge control ISA flag for clarity
  PCI: use _CRS for PCI resource allocation
  PCI: avoid P2P prefetch window for expansion ROMs
  PCI: skip ISA ioresource alignment on some systems
  PCI: remove transparent bridge sizing
  pci: write file size to inode on proc bus file write
  pci: use size stored in proc_dir_entry for proc bus files
  pci: implement "pci=noaer"
  PCI: fix IDE legacy mode resources
  MSI: Use correct data offset for 32-bit MSI in read_msi_msg()
  PCI: Fix incorrect argument order to list_add_tail() in PCI dynamic ID code
  PCI: i386: Compaq EVO N800c needs PCI bus renumbering
  PCI: Remove no longer correct documentation regarding MSI vector assignment
  PCI: re-enable onboard sound on "MSI K8T Neo2-FIR"
  PCI: quirk_vt82c586_acpi: Omit reading PCI revision ID
  PCI: quirk amd_8131_mmrbc: Omit reading pci revision ID
  cpqphp: Use PCI_CLASS_REVISION instead of PCI_REVISION_ID for read
  ...
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
index 08687e4..1a7f530 100644
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -11,7 +11,7 @@
 	    procfs-guide.xml writing_usb_driver.xml \
 	    kernel-api.xml filesystems.xml lsm.xml usb.xml \
 	    gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \
-	    genericirq.xml
+	    genericirq.xml s390-drivers.xml
 
 ###
 # The build process is as follows (targets):
diff --git a/Documentation/DocBook/s390-drivers.tmpl b/Documentation/DocBook/s390-drivers.tmpl
new file mode 100644
index 0000000..254e769
--- /dev/null
+++ b/Documentation/DocBook/s390-drivers.tmpl
@@ -0,0 +1,149 @@
+<?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="s390drivers">
+ <bookinfo>
+  <title>Writing s390 channel device drivers</title>
+
+  <authorgroup>
+   <author>
+    <firstname>Cornelia</firstname>
+    <surname>Huck</surname>
+    <affiliation>
+     <address>
+       <email>cornelia.huck@de.ibm.com</email>
+     </address>
+    </affiliation>
+   </author>
+  </authorgroup>
+
+  <copyright>
+   <year>2007</year>
+   <holder>IBM Corp.</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>
+    This document describes the interfaces available for device drivers that
+    drive s390 based channel attached devices. This includes interfaces for
+    interaction with the hardware and interfaces for interacting with the
+    common driver core. Those interfaces are provided by the s390 common I/O
+    layer.
+  </para>
+  <para>
+    The document assumes a familarity with the technical terms associated
+    with the s390 channel I/O architecture. For a description of this
+    architecture, please refer to the "z/Architecture: Principles of
+    Operation", IBM publication no. SA22-7832.
+  </para>
+  <para>
+    While most I/O devices on a s390 system are typically driven through the
+    channel I/O mechanism described here, there are various other methods
+    (like the diag interface). These are out of the scope of this document.
+  </para>
+  <para>
+    Some additional information can also be found in the kernel source
+    under Documentation/s390/driver-model.txt.
+  </para>
+  </chapter>
+  <chapter id="ccw">
+   <title>The ccw bus</title>
+  <para>
+	The ccw bus typically contains the majority of devices available to
+	a s390 system. Named after the channel command word (ccw), the basic
+	command structure used to address its devices, the ccw bus contains
+	so-called channel attached devices. They are addressed via subchannels,
+	visible on the css bus. A device driver, however, will never interact
+	with the subchannel directly, but only via the device on the ccw bus,
+	the ccw device.
+  </para>
+    <sect1 id="channelIO">
+     <title>I/O functions for channel-attached devices</title>
+    <para>
+      Some hardware structures have been translated into C structures for use
+      by the common I/O layer and device drivers. For more information on
+      the hardware structures represented here, please consult the Principles
+      of Operation.
+    </para>
+!Iinclude/asm-s390/cio.h
+    </sect1>
+    <sect1 id="ccwdev">
+     <title>ccw devices</title>
+    <para>
+      Devices that want to initiate channel I/O need to attach to the ccw bus.
+      Interaction with the driver core is done via the common I/O layer, which
+      provides the abstractions of ccw devices and ccw device drivers.
+    </para>
+    <para>
+      The functions that initiate or terminate channel I/O all act upon a
+      ccw device structure. Device drivers must not bypass those functions
+      or strange side effects may happen.
+    </para>
+!Iinclude/asm-s390/ccwdev.h
+!Edrivers/s390/cio/device.c
+!Edrivers/s390/cio/device_ops.c
+    </sect1>
+    <sect1 id="cmf">
+     <title>The channel-measurement facility</title>
+  <para>
+	The channel-measurement facility provides a means to collect
+	measurement data which is made available by the channel subsystem
+	for each channel attached device.
+  </para>
+!Iinclude/asm-s390/cmb.h
+!Edrivers/s390/cio/cmf.c
+    </sect1>
+  </chapter>
+
+  <chapter id="ccwgroup">
+   <title>The ccwgroup bus</title>
+  <para>
+	The ccwgroup bus only contains artificial devices, created by the user.
+	Many networking devices (e.g. qeth) are in fact composed of several
+	ccw devices (like read, write and data channel for qeth). The
+	ccwgroup bus provides a mechanism to create a meta-device which
+	contains those ccw devices as slave devices and can be associated
+	with the netdevice.
+  </para>
+   <sect1 id="ccwgroupdevices">
+    <title>ccw group devices</title>
+!Iinclude/asm-s390/ccwgroup.h
+!Edrivers/s390/cio/ccwgroup.c
+   </sect1>
+  </chapter>
+
+</book>
diff --git a/Documentation/filesystems/ntfs.txt b/Documentation/filesystems/ntfs.txt
index 8ee10ec..e79ee2d 100644
--- a/Documentation/filesystems/ntfs.txt
+++ b/Documentation/filesystems/ntfs.txt
@@ -407,7 +407,7 @@
 	device		/dev/hda5
 	raid-disk	0
 	device		/dev/hdb1
-	raid-disl	1
+	raid-disk	1
 
 For linear raid, just change the raid-level above to "raid-level linear", for
 mirrors, change it to "raid-level 1", and for stripe sets with parity, change
@@ -457,6 +457,8 @@
 
 Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
 
+2.1.29:
+	- Fix a deadlock when mounting read-write.
 2.1.28:
 	- Fix a deadlock.
 2.1.27:
diff --git a/Documentation/ja_JP/HOWTO b/Documentation/ja_JP/HOWTO
index 9f08dab..d9d832c 100644
--- a/Documentation/ja_JP/HOWTO
+++ b/Documentation/ja_JP/HOWTO
@@ -1,4 +1,4 @@
-NOTE:
+NOTE:
 This is a version of Documentation/HOWTO translated into Japanese.
 This document is maintained by Tsugikazu Shibata <tshibata@ab.jp.nec.com>
 and the JF Project team <www.linux.or.jp/JF>.
@@ -11,14 +11,14 @@
 fork. So if you have any comments or updates for this file, please try
 to update the original English file first.
 
-Last Updated: 2007/07/18
+Last Updated: 2007/09/23
 ==================================
 これは、
-linux-2.6.22/Documentation/HOWTO
+linux-2.6.23/Documentation/HOWTO
 の和訳です。
 
 翻訳団体: JF プロジェクト < http://www.linux.or.jp/JF/ >
-翻訳日: 2007/07/16
+翻訳日: 2007/09/19
 翻訳者: Tsugikazu Shibata <tshibata at ab dot jp dot nec dot com>
 校正者: 松倉さん <nbh--mats at nifty dot com>
          小林 雅典さん (Masanori Kobayasi) <zap03216 at nifty dot ne dot jp>
@@ -27,6 +27,7 @@
          野口さん (Kenji Noguchi) <tokyo246 at gmail dot com>
          河内さん (Takayoshi Kochi) <t-kochi at bq dot jp dot nec dot com>
          岩本さん (iwamoto) <iwamoto.kn at ncos dot nec dot co dot jp>
+         内田さん (Satoshi Uchida) <s-uchida at ap dot jp dot nec dot com>
 ==================================
 
 Linux カーネル開発のやり方
@@ -40,7 +41,7 @@
 手助けになります。
 
 もし、このドキュメントのどこかが古くなっていた場合には、このドキュメン
-トの最後にリストしたメンテナーにパッチを送ってください。
+トの最後にリストしたメンテナにパッチを送ってください。
 
 はじめに
 ---------
@@ -59,7 +60,7 @@
 ネル開発者には必要です。アーキテクチャ向けの低レベル部分の開発をするの
 でなければ、(どんなアーキテクチャでも)アセンブリ(訳注: 言語)は必要あり
 ません。以下の本は、C 言語の十分な知識や何年もの経験に取って代わるもの
-ではありませんが、少なくともリファレンスとしてはいい本です。
+ではありませんが、少なくともリファレンスとしては良い本です。
  - "The C Programming Language" by Kernighan and Ritchie [Prentice Hall]
  -『プログラミング言語C第2版』(B.W. カーニハン/D.M. リッチー著 石田晴久訳) [共立出版]
  - "Practical C Programming" by Steve Oualline [O'Reilly]
@@ -76,7 +77,7 @@
 ときどき、カーネルがツールチェインや C 言語拡張に置いている前提がどう
 なっているのかわかりにくいことがあり、また、残念なことに決定的なリファ
 レンスは存在しません。情報を得るには、gcc の info ページ( info gcc )を
-みてください。
+見てください。
 
 あなたは既存の開発コミュニティと一緒に作業する方法を学ぼうとしているこ
 とに留意してください。そのコミュニティは、コーディング、スタイル、
@@ -92,7 +93,7 @@
 
 Linux カーネルのソースコードは GPL ライセンスの下でリリースされていま
 す。ライセンスの詳細については、ソースツリーのメインディレクトリに存在
-する、COPYING のファイルをみてください。もしライセンスについてさらに質
+する、COPYING のファイルを見てください。もしライセンスについてさらに質
 問があれば、Linux Kernel メーリングリストに質問するのではなく、どうぞ
 法律家に相談してください。メーリングリストの人達は法律家ではなく、法的
 問題については彼らの声明はあてにするべきではありません。
@@ -109,7 +110,8 @@
 新しいドキュメントファイルも追加することを勧めます。
 カーネルの変更が、カーネルがユーザ空間に公開しているインターフェイスの
 変更を引き起こす場合、その変更を説明するマニュアルページのパッチや情報
-をマニュアルページのメンテナ mtk-manpages@gmx.net に送ることを勧めます。
+をマニュアルページのメンテナ mtk-manpages@gmx.net に送ることを勧めま
+す。
 
 以下はカーネルソースツリーに含まれている読んでおくべきファイルの一覧で
 す-
@@ -117,7 +119,7 @@
   README
     このファイルは Linuxカーネルの簡単な背景とカーネルを設定(訳注
     configure )し、生成(訳注 build )するために必要なことは何かが書かれ
-    ています。カーネルに関して初めての人はここからスタートするとよいで
+    ています。カーネルに関して初めての人はここからスタートすると良いで
     しょう。
 
   Documentation/Changes
@@ -128,7 +130,7 @@
   Documentation/CodingStyle
     これは Linux カーネルのコーディングスタイルと背景にある理由を記述
     しています。全ての新しいコードはこのドキュメントにあるガイドライン
-    に従っていることを期待されています。大部分のメンテナーはこれらのルー
+    に従っていることを期待されています。大部分のメンテナはこれらのルー
     ルに従っているものだけを受け付け、多くの人は正しいスタイルのコード
     だけをレビューします。
 
@@ -168,16 +170,16 @@
     支援してください。
 
   Documentation/ManagementStyle
-    このドキュメントは Linux カーネルのメンテナー達がどう行動するか、
+    このドキュメントは Linux カーネルのメンテナ達がどう行動するか、
     彼らの手法の背景にある共有されている精神について記述しています。こ
     れはカーネル開発の初心者なら(もしくは、単に興味があるだけの人でも)
-    重要です。なぜならこのドキュメントは、カーネルメンテナー達の独特な
+    重要です。なぜならこのドキュメントは、カーネルメンテナ達の独特な
     行動についての多くの誤解や混乱を解消するからです。
 
   Documentation/stable_kernel_rules.txt
     このファイルはどのように stable カーネルのリリースが行われるかのルー
     ルが記述されています。そしてこれらのリリースの中のどこかで変更を取
-    り入れてもらいたい場合に何をすればいいかが示されています。
+    り入れてもらいたい場合に何をすれば良いかが示されています。
 
   Documentation/kernel-docs.txt
   カーネル開発に付随する外部ドキュメントのリストです。もしあなたが
@@ -218,9 +220,9 @@
 ここには、また、カーネルのコンパイルのやり方やパッチの当て方などの間接
 的な基本情報も記述されています。
 
-あなたがどこからスタートしてよいかわからないが、Linux カーネル開発コミュ
+あなたがどこからスタートして良いかわからないが、Linux カーネル開発コミュ
 ニティに参加して何かすることをさがしている場合には、Linux kernel
-Janitor's プロジェクトにいけばよいでしょう -
+Janitor's プロジェクトにいけば良いでしょう -
 	http://janitor.kernelnewbies.org/
 ここはそのようなスタートをするのにうってつけの場所です。ここには、
 Linux カーネルソースツリーの中に含まれる、きれいにし、修正しなければな
@@ -243,7 +245,7 @@
 自己参照方式で、索引がついた web 形式で、ソースコードを参照することが
 できます。この最新の素晴しいカーネルコードのリポジトリは以下で見つかり
 ます-
-	http://sosdg.org/~coywolf/lxr/
+	http://sosdg.org/~qiyong/lxr/
 
 開発プロセス
 -----------------------
@@ -265,9 +267,9 @@
 以下のとおり-
 
   - 新しいカーネルがリリースされた直後に、2週間の特別期間が設けられ、
-    この期間中に、メンテナー達は Linus に大きな差分を送ることができま
-    す。このような差分は通常 -mm カーネルに数週間含まれてきたパッチで
-    す。 大きな変更は git(カーネルのソース管理ツール、詳細は
+    この期間中に、メンテナ達は Linus に大きな差分を送ることができます。
+    このような差分は通常 -mm カーネルに数週間含まれてきたパッチです。
+    大きな変更は git(カーネルのソース管理ツール、詳細は
     http://git.or.cz/  参照) を使って送るのが好ましいやり方ですが、パッ
     チファイルの形式のまま送るのでも十分です。
 
@@ -285,6 +287,10 @@
     に安定した状態にあると判断したときにリリースされます。目標は毎週新
     しい -rc カーネルをリリースすることです。
 
+   - 以下の URL で各 -rc リリースに存在する既知の後戻り問題のリスト
+     が追跡されます-
+     http://kernelnewbies.org/known_regressions
+
   - このプロセスはカーネルが 「準備ができた」と考えられるまで継続しま
     す。このプロセスはだいたい 6週間継続します。
 
@@ -331,8 +337,8 @@
 linux-kernel メーリングリストで収集された多数のパッチと同時に一つにま
 とめます。
 このツリーは新機能とパッチが検証される場となります。ある期間の間パッチ
-が -mm に入って価値を証明されたら、Andrew やサブシステムメンテナが、メ
-インラインへ入れるように Linus にプッシュします。
+が -mm に入って価値を証明されたら、Andrew やサブシステムメンテナが、
+メインラインへ入れるように Linus にプッシュします。
 
 メインカーネルツリーに含めるために Linus に送る前に、すべての新しいパッ
 チが -mm ツリーでテストされることが強く推奨されます。
@@ -460,7 +466,7 @@
 せん-
 彼らはあなたのパッチの行毎にコメントを入れたいので、そのためにはそうす
 るしかありません。あなたのメールプログラムが空白やタブを圧縮しないよう
-に確認した方がいいです。最初の良いテストとしては、自分にメールを送って
+に確認した方が良いです。最初の良いテストとしては、自分にメールを送って
 みて、そのパッチを自分で当ててみることです。もしそれがうまく行かないな
 ら、あなたのメールプログラムを直してもらうか、正しく動くように変えるべ
 きです。
@@ -507,14 +513,14 @@
 とも普通のことです。これはあなたのパッチが受け入れられないということで
 は *ありません*、そしてあなた自身に反対することを意味するのでも *ありま
 せん*。単に自分のパッチに対して指摘された問題を全て修正して再送すれば
-いいのです。
+良いのです。
 
 
 カーネルコミュニティと企業組織のちがい
 -----------------------------------------------------------------
 
 カーネルコミュニティは大部分の伝統的な会社の開発環境とは異ったやり方で
-動いています。以下は問題を避けるためにできるとよいことののリストです-
+動いています。以下は問題を避けるためにできると良いことのリストです-
 
   あなたの提案する変更について言うときのうまい言い方:
 
@@ -525,7 +531,7 @@
     - "以下は一連の小さなパッチ群ですが..."
     - "これは典型的なマシンでの性能を向上させます.."
 
-  やめた方がいい悪い言い方:
+  やめた方が良い悪い言い方:
 
     - このやり方で AIX/ptx/Solaris ではできたので、できるはずだ
     - 私はこれを20年もの間やってきた、だから
@@ -575,10 +581,10 @@
 
 1) 小さいパッチはあなたのパッチが適用される見込みを大きくします、カー
    ネルの人達はパッチが正しいかどうかを確認する時間や労力をかけないか
-   らです。5行のパッチはメンテナがたった1秒見るだけで適用できます。し
-   かし、500行のパッチは、正しいことをレビューするのに数時間かかるかも
-   しれません(時間はパッチのサイズなどにより指数関数に比例してかかりま
-   す)
+   らです。5行のパッチはメンテナがたった1秒見るだけで適用できます。
+   しかし、500行のパッチは、正しいことをレビューするのに数時間かかるか
+   もしれません(時間はパッチのサイズなどにより指数関数に比例してかかり
+   ます)
 
    小さいパッチは何かあったときにデバッグもとても簡単になります。パッ
    チを1個1個取り除くのは、とても大きなパッチを当てた後に(かつ、何かお
@@ -587,23 +593,23 @@
 2) 小さいパッチを送るだけでなく、送るまえに、書き直して、シンプルにす
    る(もしくは、単に順番を変えるだけでも)ことも、とても重要です。
 
-以下はカーネル開発者の Al Viro のたとえ話しです:
+以下はカーネル開発者の Al Viro のたとえ話です:
 
         "生徒の数学の宿題を採点する先生のことを考えてみてください、先
-        生は生徒が解に到達するまでの試行錯誤をみたいとは思わないでしょ
-        う。先生は簡潔な最高の解をみたいのです。良い生徒はこれを知って
+        生は生徒が解に到達するまでの試行錯誤を見たいとは思わないでしょ
+        う。先生は簡潔な最高の解を見たいのです。良い生徒はこれを知って
         おり、そして最終解の前の中間作業を提出することは決してないので
         す"
 
-        カーネル開発でもこれは同じです。メンテナー達とレビューア達は、
-        問題を解決する解の背後になる思考プロセスをみたいとは思いません。
-        彼らは単純であざやかな解決方法をみたいのです。
+        カーネル開発でもこれは同じです。メンテナ達とレビューア達は、
+        問題を解決する解の背後になる思考プロセスを見たいとは思いません。
+        彼らは単純であざやかな解決方法を見たいのです。
 
 あざやかな解を説明するのと、コミュニティと共に仕事をし、未解決の仕事を
 議論することのバランスをキープするのは難しいかもしれません。
 ですから、開発プロセスの早期段階で改善のためのフィードバックをもらうよ
-うにするのもいいですが、変更点を小さい部分に分割して全体ではまだ完成し
-ていない仕事を(部分的に)取り込んでもらえるようにすることもいいことです。
+うにするのも良いですが、変更点を小さい部分に分割して全体ではまだ完成し
+ていない仕事を(部分的に)取り込んでもらえるようにすることも良いことです。
 
 また、でき上がっていないものや、"将来直す" ようなパッチを、本流に含め
 てもらうように送っても、それは受け付けられないことを理解してください。
@@ -629,7 +635,7 @@
   - テスト結果
 
 これについて全てがどのようにあるべきかについての詳細は、以下のドキュメ
-ントの ChangeLog セクションをみてください-
+ントの ChangeLog セクションを見てください-
   "The Perfect Patch"
       http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt
 
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index d006e8b6..9cbc82e 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1010,6 +1010,10 @@
 	meye.*=		[HW] Set MotionEye Camera parameters
 			See Documentation/video4linux/meye.txt.
 
+	mfgpt_irq=	[IA-32] Specify the IRQ to use for the
+			Multi-Function General Purpose Timers on AMD Geode
+			platforms.
+
 	mga=		[HW,DRM]
 
 	mousedev.tap_time=
@@ -1161,6 +1165,9 @@
 
 	nomce		[X86-32] Machine Check Exception
 
+	nomfgpt		[X86-32] Disable Multi-Function General Purpose
+			Timer usage (for AMD Geode machines).
+
 	noreplace-paravirt	[X86-32,PV_OPS] Don't patch paravirt_ops
 
 	noreplace-smp	[X86-32,SMP] Don't replace SMP instructions
@@ -1438,6 +1445,10 @@
 	pt.		[PARIDE]
 			See Documentation/paride.txt.
 
+	pty.legacy_count=
+			[KNL] Number of legacy pty's. Overwrites compiled-in
+			default number.
+
 	quiet		[KNL] Disable most log messages
 
 	r128=		[HW,DRM]
diff --git a/Documentation/kobject.txt b/Documentation/kobject.txt
index 8ee49ee..ca86a88 100644
--- a/Documentation/kobject.txt
+++ b/Documentation/kobject.txt
@@ -54,7 +54,6 @@
 
 struct kobject {
 	const char		* k_name;
-	char			name[KOBJ_NAME_LEN];
 	struct kref		kref;
 	struct list_head	entry;
 	struct kobject		* parent;
@@ -223,18 +222,15 @@
 is equivalent to doing:
 
 struct kset devices_subsys = {
-     .kobj = {
-	   .name = "devices",
-     },
      .ktype = &ktype_devices,
      .uevent_ops = &device_uevent_ops,
 };
-
+kobject_set_name(&devices_subsys, name);
 
 The objects that are registered with a subsystem that use the
 subsystem's default list must have their kset ptr set properly. These
 objects may have embedded kobjects or ksets. The
-following helpers make setting the kset easier:
+following helper makes setting the kset easier:
 
 
 kobj_set_kset_s(obj,subsys)
@@ -242,22 +238,8 @@
 - Assumes that obj->kobj exists, and is a struct kobject.
 - Sets the kset of that kobject to the kset <subsys>.
 
-
-kset_set_kset_s(obj,subsys)
-
-- Assumes that obj->kset exists, and is a struct kset.
-- Sets the kset of the embedded kobject to the kset <subsys>.
-
-subsys_set_kset(obj,subsys)
-
-- Assumes obj->subsys exists, and is a struct subsystem.
-- Sets obj->subsys.kset.kobj.kset to the subsystem's embedded kset.
-
-void subsystem_init(struct kset *s);
 int subsystem_register(struct kset *s);
 void subsystem_unregister(struct kset *s);
-struct kset *subsys_get(struct kset *s);
-void kset_put(struct kset *s);
 
 These are just wrappers around the respective kset_* functions.
 
diff --git a/Documentation/s390/00-INDEX b/Documentation/s390/00-INDEX
new file mode 100644
index 0000000..3a2b963
--- /dev/null
+++ b/Documentation/s390/00-INDEX
@@ -0,0 +1,26 @@
+00-INDEX
+	- this file.
+3270.ChangeLog
+	- ChangeLog for the UTS Global 3270-support patch (outdated).
+3270.txt
+	- how to use the IBM 3270 display system support.
+cds.txt
+	- s390 common device support (common I/O layer).
+CommonIO
+	- common I/O layer command line parameters, procfs and debugfs	entries
+config3270.sh
+	- example configuration for 3270 devices.
+DASD
+	- information on the DASD disk device driver.
+Debugging390.txt
+	- hints for debugging on s390 systems.
+driver-model.txt
+	- information on s390 devices and the driver model.
+monreader.txt
+	- information on accessing the z/VM monitor stream from Linux.
+s390dbf.txt
+	- information on using the s390 debug feature.
+TAPE
+	- information on the driver for channel-attached tapes.
+zfcpdump
+	- information on the s390 SCSI dump tool.
diff --git a/Documentation/s390/CommonIO b/Documentation/s390/CommonIO
index 22f82f2..86320aa 100644
--- a/Documentation/s390/CommonIO
+++ b/Documentation/s390/CommonIO
@@ -1,5 +1,5 @@
-S/390 common I/O-Layer - command line parameters and /proc entries
-==================================================================
+S/390 common I/O-Layer - command line parameters, procfs and debugfs entries
+============================================================================
 
 Command line parameters
 -----------------------
@@ -7,9 +7,9 @@
 * cio_msg = yes | no
   
   Determines whether information on found devices and sensed device 
-  characteristics should be shown during startup, i. e. messages of the types 
-  "Detected device 0.0.4711 on subchannel 0.0.0042" and "SenseID: Device
-  0.0.4711 reports: ...".
+  characteristics should be shown during startup or when new devices are
+  found, i. e. messages of the types "Detected device 0.0.4711 on subchannel
+  0.0.0042" and "SenseID: Device 0.0.4711 reports: ...".
 
   Default is off.
 
@@ -26,8 +26,10 @@
   An ignored device can be un-ignored later; see the "/proc entries"-section for
   details.
 
-  The devices must be given either as bus ids (0.0.abcd) or as hexadecimal
-  device numbers (0xabcd or abcd, for 2.4 backward compatibility).
+  The devices must be given either as bus ids (0.x.abcd) or as hexadecimal
+  device numbers (0xabcd or abcd, for 2.4 backward compatibility). If you
+  give a device number 0xabcd, it will be interpreted as 0.0.abcd.
+
   You can use the 'all' keyword to ignore all devices.
   The '!' operator will cause the I/O-layer to _not_ ignore a device.
   The command line is parsed from left to right.
@@ -81,31 +83,36 @@
   will add 0.0.a000-0.0.accc and 0.0.af00-0.0.afff to the list of ignored
   devices.
 
-  The devices can be specified either by bus id (0.0.abcd) or, for 2.4 backward
-  compatibility, by the device number in hexadecimal (0xabcd or abcd).
+  The devices can be specified either by bus id (0.x.abcd) or, for 2.4 backward
+  compatibility, by the device number in hexadecimal (0xabcd or abcd). Device
+  numbers given as 0xabcd will be interpreted as 0.0.abcd.
+
+* For some of the information present in the /proc filesystem in 2.4 (namely,
+  /proc/subchannels and /proc/chpids), see driver-model.txt.
+  Information formerly in /proc/irq_count is now in /proc/interrupts.
 
 
-* /proc/s390dbf/cio_*/ (S/390 debug feature)
+debugfs entries
+---------------
+
+* /sys/kernel/debug/s390dbf/cio_*/ (S/390 debug feature)
 
   Some views generated by the debug feature to hold various debug outputs.
 
-  - /proc/s390dbf/cio_crw/sprintf
+  - /sys/kernel/debug/s390dbf/cio_crw/sprintf
     Messages from the processing of pending channel report words (machine check
-    handling), which will also show when CONFIG_DEBUG_CRW is defined.
+    handling).
 
-  - /proc/s390dbf/cio_msg/sprintf
-    Various debug messages from the common I/O-layer; generally, messages which 
-    will also show when CONFIG_DEBUG_IO is defined.
+  - /sys/kernel/debug/s390dbf/cio_msg/sprintf
+    Various debug messages from the common I/O-layer, including messages
+    printed when cio_msg=yes.
 
-  - /proc/s390dbf/cio_trace/hex_ascii
+  - /sys/kernel/debug/s390dbf/cio_trace/hex_ascii
     Logs the calling of functions in the common I/O-layer and, if applicable, 
     which subchannel they were called for, as well as dumps of some data
     structures (like irb in an error case).
 
   The level of logging can be changed to be more or less verbose by piping to 
-  /proc/s390dbf/cio_*/level a number between 0 and 6; see the documentation on
-  the S/390 debug feature (Documentation/s390/s390dbf.txt) for details.
-
-* For some of the information present in the /proc filesystem in 2.4 (namely,
-  /proc/subchannels and /proc/chpids), see driver-model.txt.
-  Information formerly in /proc/irq_count is now in /proc/interrupts.
+  /sys/kernel/debug/s390dbf/cio_*/level a number between 0 and 6; see the
+  documentation on the S/390 debug feature (Documentation/s390/s390dbf.txt)
+  for details.
diff --git a/Documentation/s390/cds.txt b/Documentation/s390/cds.txt
index 58919d6..3081927 100644
--- a/Documentation/s390/cds.txt
+++ b/Documentation/s390/cds.txt
@@ -286,10 +286,10 @@
             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 number of device specific sense bytes
-available in the extended control word irb->scsw.ecw[0]. No device sensing by
-the device driver itself is required.
+If the concurrent sense flag in the extended status word (esw) in the irb is
+set, the field erw.scnt in the esw describes the number of device specific
+sense bytes available in the extended control word irb->scsw.ecw[]. No device
+sensing by the device driver itself is required.
 
 The device interrupt handler can use the following definitions to investigate
 the primary unit check source coded in sense byte 0 :
diff --git a/Documentation/usb/authorization.txt b/Documentation/usb/authorization.txt
new file mode 100644
index 0000000..2af4006
--- /dev/null
+++ b/Documentation/usb/authorization.txt
@@ -0,0 +1,92 @@
+
+Authorizing (or not) your USB devices to connect to the system
+
+(C) 2007 Inaky Perez-Gonzalez <inaky@linux.intel.com> Intel Corporation
+
+This feature allows you to control if a USB device can be used (or
+not) in a system. This feature will allow you to implement a lock-down
+of USB devices, fully controlled by user space.
+
+As of now, when a USB device is connected it is configured and
+it's interfaces inmediately made available to the users. With this
+modification, only if root authorizes the device to be configured will
+then it be possible to use it.
+
+Usage:
+
+Authorize a device to connect:
+
+$ echo 1 > /sys/usb/devices/DEVICE/authorized
+
+Deauthorize a device:
+
+$ echo 0 > /sys/usb/devices/DEVICE/authorized
+
+Set new devices connected to hostX to be deauthorized by default (ie:
+lock down):
+
+$ echo 0 > /sys/bus/devices/usbX/authorized_default
+
+Remove the lock down:
+
+$ echo 1 > /sys/bus/devices/usbX/authorized_default
+
+By default, Wired USB devices are authorized by default to
+connect. Wireless USB hosts deauthorize by default all new connected
+devices (this is so because we need to do an authentication phase
+before authorizing).
+
+
+Example system lockdown (lame)
+-----------------------
+
+Imagine you want to implement a lockdown so only devices of type XYZ
+can be connected (for example, it is a kiosk machine with a visible
+USB port):
+
+boot up
+rc.local ->
+
+ for host in /sys/bus/devices/usb*
+ do
+    echo 0 > $host/authorized_default
+ done
+
+Hookup an script to udev, for new USB devices
+
+ if device_is_my_type $DEV
+ then
+   echo 1 > $device_path/authorized
+ done
+
+
+Now, device_is_my_type() is where the juice for a lockdown is. Just
+checking if the class, type and protocol match something is the worse
+security verification you can make (or the best, for someone willing
+to break it). If you need something secure, use crypto and Certificate
+Authentication or stuff like that. Something simple for an storage key
+could be:
+
+function device_is_my_type()
+{
+   echo 1 > authorized		# temporarily authorize it
+                                # FIXME: make sure none can mount it
+   mount DEVICENODE /mntpoint
+   sum=$(md5sum /mntpoint/.signature)
+   if [ $sum = $(cat /etc/lockdown/keysum) ]
+   then
+        echo "We are good, connected"
+        umount /mntpoint
+        # Other stuff so others can use it
+   else
+        echo 0 > authorized
+   fi
+}
+
+
+Of course, this is lame, you'd want to do a real certificate
+verification stuff with PKI, so you don't depend on a shared secret,
+etc, but you get the idea. Anybody with access to a device gadget kit
+can fake descriptors and device info. Don't trust that. You are
+welcome.
+
diff --git a/Documentation/usb/power-management.txt b/Documentation/usb/power-management.txt
new file mode 100644
index 0000000..97842de
--- /dev/null
+++ b/Documentation/usb/power-management.txt
@@ -0,0 +1,517 @@
+			Power Management for USB
+
+		 Alan Stern <stern@rowland.harvard.edu>
+
+			    October 5, 2007
+
+
+
+	What is Power Management?
+	-------------------------
+
+Power Management (PM) is the practice of saving energy by suspending
+parts of a computer system when they aren't being used.  While a
+component is "suspended" it is in a nonfunctional low-power state; it
+might even be turned off completely.  A suspended component can be
+"resumed" (returned to a functional full-power state) when the kernel
+needs to use it.  (There also are forms of PM in which components are
+placed in a less functional but still usable state instead of being
+suspended; an example would be reducing the CPU's clock rate.  This
+document will not discuss those other forms.)
+
+When the parts being suspended include the CPU and most of the rest of
+the system, we speak of it as a "system suspend".  When a particular
+device is turned off while the system as a whole remains running, we
+call it a "dynamic suspend" (also known as a "runtime suspend" or
+"selective suspend").  This document concentrates mostly on how
+dynamic PM is implemented in the USB subsystem, although system PM is
+covered to some extent (see Documentation/power/*.txt for more
+information about system PM).
+
+Note: Dynamic PM support for USB is present only if the kernel was
+built with CONFIG_USB_SUSPEND enabled.  System PM support is present
+only if the kernel was built with CONFIG_SUSPEND or CONFIG_HIBERNATION
+enabled.
+
+
+	What is Remote Wakeup?
+	----------------------
+
+When a device has been suspended, it generally doesn't resume until
+the computer tells it to.  Likewise, if the entire computer has been
+suspended, it generally doesn't resume until the user tells it to, say
+by pressing a power button or opening the cover.
+
+However some devices have the capability of resuming by themselves, or
+asking the kernel to resume them, or even telling the entire computer
+to resume.  This capability goes by several names such as "Wake On
+LAN"; we will refer to it generically as "remote wakeup".  When a
+device is enabled for remote wakeup and it is suspended, it may resume
+itself (or send a request to be resumed) in response to some external
+event.  Examples include a suspended keyboard resuming when a key is
+pressed, or a suspended USB hub resuming when a device is plugged in.
+
+
+	When is a USB device idle?
+	--------------------------
+
+A device is idle whenever the kernel thinks it's not busy doing
+anything important and thus is a candidate for being suspended.  The
+exact definition depends on the device's driver; drivers are allowed
+to declare that a device isn't idle even when there's no actual
+communication taking place.  (For example, a hub isn't considered idle
+unless all the devices plugged into that hub are already suspended.)
+In addition, a device isn't considered idle so long as a program keeps
+its usbfs file open, whether or not any I/O is going on.
+
+If a USB device has no driver, its usbfs file isn't open, and it isn't
+being accessed through sysfs, then it definitely is idle.
+
+
+	Forms of dynamic PM
+	-------------------
+
+Dynamic suspends can occur in two ways: manual and automatic.
+"Manual" means that the user has told the kernel to suspend a device,
+whereas "automatic" means that the kernel has decided all by itself to
+suspend a device.  Automatic suspend is called "autosuspend" for
+short.  In general, a device won't be autosuspended unless it has been
+idle for some minimum period of time, the so-called idle-delay time.
+
+Of course, nothing the kernel does on its own initiative should
+prevent the computer or its devices from working properly.  If a
+device has been autosuspended and a program tries to use it, the
+kernel will automatically resume the device (autoresume).  For the
+same reason, an autosuspended device will usually have remote wakeup
+enabled, if the device supports remote wakeup.
+
+It is worth mentioning that many USB drivers don't support
+autosuspend.  In fact, at the time of this writing (Linux 2.6.23) the
+only drivers which do support it are the hub driver, kaweth, asix,
+usblp, usblcd, and usb-skeleton (which doesn't count).  If a
+non-supporting driver is bound to a device, the device won't be
+autosuspended.  In effect, the kernel pretends the device is never
+idle.
+
+We can categorize power management events in two broad classes:
+external and internal.  External events are those triggered by some
+agent outside the USB stack: system suspend/resume (triggered by
+userspace), manual dynamic suspend/resume (also triggered by
+userspace), and remote wakeup (triggered by the device).  Internal
+events are those triggered within the USB stack: autosuspend and
+autoresume.
+
+
+	The user interface for dynamic PM
+	---------------------------------
+
+The user interface for controlling dynamic PM is located in the power/
+subdirectory of each USB device's sysfs directory, that is, in
+/sys/bus/usb/devices/.../power/ where "..." is the device's ID.  The
+relevant attribute files are: wakeup, level, and autosuspend.
+
+	power/wakeup
+
+		This file is empty if the device does not support
+		remote wakeup.  Otherwise the file contains either the
+		word "enabled" or the word "disabled", and you can
+		write those words to the file.  The setting determines
+		whether or not remote wakeup will be enabled when the
+		device is next suspended.  (If the setting is changed
+		while the device is suspended, the change won't take
+		effect until the following suspend.)
+
+	power/level
+
+		This file contains one of three words: "on", "auto",
+		or "suspend".  You can write those words to the file
+		to change the device's setting.
+
+		"on" means that the device should be resumed and
+		autosuspend is not allowed.  (Of course, system
+		suspends are still allowed.)
+
+		"auto" is the normal state in which the kernel is
+		allowed to autosuspend and autoresume the device.
+
+		"suspend" means that the device should remain
+		suspended, and autoresume is not allowed.  (But remote
+		wakeup may still be allowed, since it is controlled
+		separately by the power/wakeup attribute.)
+
+	power/autosuspend
+
+		This file contains an integer value, which is the
+		number of seconds the device should remain idle before
+		the kernel will autosuspend it (the idle-delay time).
+		The default is 2.  0 means to autosuspend as soon as
+		the device becomes idle, and -1 means never to
+		autosuspend.  You can write a number to the file to
+		change the autosuspend idle-delay time.
+
+Writing "-1" to power/autosuspend and writing "on" to power/level do
+essentially the same thing -- they both prevent the device from being
+autosuspended.  Yes, this is a redundancy in the API.
+
+(In 2.6.21 writing "0" to power/autosuspend would prevent the device
+from being autosuspended; the behavior was changed in 2.6.22.  The
+power/autosuspend attribute did not exist prior to 2.6.21, and the
+power/level attribute did not exist prior to 2.6.22.)
+
+
+	Changing the default idle-delay time
+	------------------------------------
+
+The default autosuspend idle-delay time is controlled by a module
+parameter in usbcore.  You can specify the value when usbcore is
+loaded.  For example, to set it to 5 seconds instead of 2 you would
+do:
+
+	modprobe usbcore autosuspend=5
+
+Equivalently, you could add to /etc/modprobe.conf a line saying:
+
+	options usbcore autosuspend=5
+
+Some distributions load the usbcore module very early during the boot
+process, by means of a program or script running from an initramfs
+image.  To alter the parameter value you would have to rebuild that
+image.
+
+If usbcore is compiled into the kernel rather than built as a loadable
+module, you can add
+
+	usbcore.autosuspend=5
+
+to the kernel's boot command line.
+
+Finally, the parameter value can be changed while the system is
+running.  If you do:
+
+	echo 5 >/sys/module/usbcore/parameters/autosuspend
+
+then each new USB device will have its autosuspend idle-delay
+initialized to 5.  (The idle-delay values for already existing devices
+will not be affected.)
+
+Setting the initial default idle-delay to -1 will prevent any
+autosuspend of any USB device.  This is a simple alternative to
+disabling CONFIG_USB_SUSPEND and rebuilding the kernel, and it has the
+added benefit of allowing you to enable autosuspend for selected
+devices.
+
+
+	Warnings
+	--------
+
+The USB specification states that all USB devices must support power
+management.  Nevertheless, the sad fact is that many devices do not
+support it very well.  You can suspend them all right, but when you
+try to resume them they disconnect themselves from the USB bus or
+they stop working entirely.  This seems to be especially prevalent
+among printers and scanners, but plenty of other types of device have
+the same deficiency.
+
+For this reason, by default the kernel disables autosuspend (the
+power/level attribute is initialized to "on") for all devices other
+than hubs.  Hubs, at least, appear to be reasonably well-behaved in
+this regard.
+
+(In 2.6.21 and 2.6.22 this wasn't the case.  Autosuspend was enabled
+by default for almost all USB devices.  A number of people experienced
+problems as a result.)
+
+This means that non-hub devices won't be autosuspended unless the user
+or a program explicitly enables it.  As of this writing there aren't
+any widespread programs which will do this; we hope that in the near
+future device managers such as HAL will take on this added
+responsibility.  In the meantime you can always carry out the
+necessary operations by hand or add them to a udev script.  You can
+also change the idle-delay time; 2 seconds is not the best choice for
+every device.
+
+Sometimes it turns out that even when a device does work okay with
+autosuspend there are still problems.  For example, there are
+experimental patches adding autosuspend support to the usbhid driver,
+which manages keyboards and mice, among other things.  Tests with a
+number of keyboards showed that typing on a suspended keyboard, while
+causing the keyboard to do a remote wakeup all right, would
+nonetheless frequently result in lost keystrokes.  Tests with mice
+showed that some of them would issue a remote-wakeup request in
+response to button presses but not to motion, and some in response to
+neither.
+
+The kernel will not prevent you from enabling autosuspend on devices
+that can't handle it.  It is even possible in theory to damage a
+device by suspending it at the wrong time -- for example, suspending a
+USB hard disk might cause it to spin down without parking the heads.
+(Highly unlikely, but possible.)  Take care.
+
+
+	The driver interface for Power Management
+	-----------------------------------------
+
+The requirements for a USB driver to support external power management
+are pretty modest; the driver need only define
+
+	.suspend
+	.resume
+	.reset_resume
+
+methods in its usb_driver structure, and the reset_resume method is
+optional.  The methods' jobs are quite simple:
+
+	The suspend method is called to warn the driver that the
+	device is going to be suspended.  If the driver returns a
+	negative error code, the suspend will be aborted.  Normally
+	the driver will return 0, in which case it must cancel all
+	outstanding URBs (usb_kill_urb()) and not submit any more.
+
+	The resume method is called to tell the driver that the
+	device has been resumed and the driver can return to normal
+	operation.  URBs may once more be submitted.
+
+	The reset_resume method is called to tell the driver that
+	the device has been resumed and it also has been reset.
+	The driver should redo any necessary device initialization,
+	since the device has probably lost most or all of its state
+	(although the interfaces will be in the same altsettings as
+	before the suspend).
+
+The reset_resume method is used by the USB Persist facility (see
+Documentation/usb/persist.txt) and it can also be used under certain
+circumstances when CONFIG_USB_PERSIST is not enabled.  Currently, if a
+device is reset during a resume and the driver does not have a
+reset_resume method, the driver won't receive any notification about
+the resume.  Later kernels will call the driver's disconnect method;
+2.6.23 doesn't do this.
+
+USB drivers are bound to interfaces, so their suspend and resume
+methods get called when the interfaces are suspended or resumed.  In
+principle one might want to suspend some interfaces on a device (i.e.,
+force the drivers for those interface to stop all activity) without
+suspending the other interfaces.  The USB core doesn't allow this; all
+interfaces are suspended when the device itself is suspended and all
+interfaces are resumed when the device is resumed.  It isn't possible
+to suspend or resume some but not all of a device's interfaces.  The
+closest you can come is to unbind the interfaces' drivers.
+
+
+	The driver interface for autosuspend and autoresume
+	---------------------------------------------------
+
+To support autosuspend and autoresume, a driver should implement all
+three of the methods listed above.  In addition, a driver indicates
+that it supports autosuspend by setting the .supports_autosuspend flag
+in its usb_driver structure.  It is then responsible for informing the
+USB core whenever one of its interfaces becomes busy or idle.  The
+driver does so by calling these three functions:
+
+	int  usb_autopm_get_interface(struct usb_interface *intf);
+	void usb_autopm_put_interface(struct usb_interface *intf);
+	int  usb_autopm_set_interface(struct usb_interface *intf);
+
+The functions work by maintaining a counter in the usb_interface
+structure.  When intf->pm_usage_count is > 0 then the interface is
+deemed to be busy, and the kernel will not autosuspend the interface's
+device.  When intf->pm_usage_count is <= 0 then the interface is
+considered to be idle, and the kernel may autosuspend the device.
+
+(There is a similar pm_usage_count field in struct usb_device,
+associated with the device itself rather than any of its interfaces.
+This field is used only by the USB core.)
+
+The driver owns intf->pm_usage_count; it can modify the value however
+and whenever it likes.  A nice aspect of the usb_autopm_* routines is
+that the changes they make are protected by the usb_device structure's
+PM mutex (udev->pm_mutex); however drivers may change pm_usage_count
+without holding the mutex.
+
+	usb_autopm_get_interface() increments pm_usage_count and
+	attempts an autoresume if the new value is > 0 and the
+	device is suspended.
+
+	usb_autopm_put_interface() decrements pm_usage_count and
+	attempts an autosuspend if the new value is <= 0 and the
+	device isn't suspended.
+
+	usb_autopm_set_interface() leaves pm_usage_count alone.
+	It attempts an autoresume if the value is > 0 and the device
+	is suspended, and it attempts an autosuspend if the value is
+	<= 0 and the device isn't suspended.
+
+There also are a couple of utility routines drivers can use:
+
+	usb_autopm_enable() sets pm_usage_cnt to 1 and then calls
+	usb_autopm_set_interface(), which will attempt an autoresume.
+
+	usb_autopm_disable() sets pm_usage_cnt to 0 and then calls
+	usb_autopm_set_interface(), which will attempt an autosuspend.
+
+The conventional usage pattern is that a driver calls
+usb_autopm_get_interface() in its open routine and
+usb_autopm_put_interface() in its close or release routine.  But
+other patterns are possible.
+
+The autosuspend attempts mentioned above will often fail for one
+reason or another.  For example, the power/level attribute might be
+set to "on", or another interface in the same device might not be
+idle.  This is perfectly normal.  If the reason for failure was that
+the device hasn't been idle for long enough, a delayed workqueue
+routine is automatically set up to carry out the operation when the
+autosuspend idle-delay has expired.
+
+Autoresume attempts also can fail.  This will happen if power/level is
+set to "suspend" or if the device doesn't manage to resume properly.
+Unlike autosuspend, there's no delay for an autoresume.
+
+
+	Other parts of the driver interface
+	-----------------------------------
+
+Sometimes a driver needs to make sure that remote wakeup is enabled
+during autosuspend.  For example, there's not much point
+autosuspending a keyboard if the user can't cause the keyboard to do a
+remote wakeup by typing on it.  If the driver sets
+intf->needs_remote_wakeup to 1, the kernel won't autosuspend the
+device if remote wakeup isn't available or has been disabled through
+the power/wakeup attribute.  (If the device is already autosuspended,
+though, setting this flag won't cause the kernel to autoresume it.
+Normally a driver would set this flag in its probe method, at which
+time the device is guaranteed not to be autosuspended.)
+
+The usb_autopm_* routines have to run in a sleepable process context;
+they must not be called from an interrupt handler or while holding a
+spinlock.  In fact, the entire autosuspend mechanism is not well geared
+toward interrupt-driven operation.  However there is one thing a
+driver can do in an interrupt handler:
+
+	usb_mark_last_busy(struct usb_device *udev);
+
+This sets udev->last_busy to the current time.  udev->last_busy is the
+field used for idle-delay calculations; updating it will cause any
+pending autosuspend to be moved back.  The usb_autopm_* routines will
+also set the last_busy field to the current time.
+
+Calling urb_mark_last_busy() from within an URB completion handler is
+subject to races: The kernel may have just finished deciding the
+device has been idle for long enough but not yet gotten around to
+calling the driver's suspend method.  The driver would have to be
+responsible for synchronizing its suspend method with its URB
+completion handler and causing the autosuspend to fail with -EBUSY if
+an URB had completed too recently.
+
+External suspend calls should never be allowed to fail in this way,
+only autosuspend calls.  The driver can tell them apart by checking
+udev->auto_pm; this flag will be set to 1 for internal PM events
+(autosuspend or autoresume) and 0 for external PM events.
+
+Many of the ingredients in the autosuspend framework are oriented
+towards interfaces: The usb_interface structure contains the
+pm_usage_cnt field, and the usb_autopm_* routines take an interface
+pointer as their argument.  But somewhat confusingly, a few of the
+pieces (usb_mark_last_busy() and udev->auto_pm) use the usb_device
+structure instead.  Drivers need to keep this straight; they can call
+interface_to_usbdev() to find the device structure for a given
+interface.
+
+
+	Locking requirements
+	--------------------
+
+All three suspend/resume methods are always called while holding the
+usb_device's PM mutex.  For external events -- but not necessarily for
+autosuspend or autoresume -- the device semaphore (udev->dev.sem) will
+also be held.  This implies that external suspend/resume events are
+mutually exclusive with calls to probe, disconnect, pre_reset, and
+post_reset; the USB core guarantees that this is true of internal
+suspend/resume events as well.
+
+If a driver wants to block all suspend/resume calls during some
+critical section, it can simply acquire udev->pm_mutex.
+Alternatively, if the critical section might call some of the
+usb_autopm_* routines, the driver can avoid deadlock by doing:
+
+	down(&udev->dev.sem);
+	rc = usb_autopm_get_interface(intf);
+
+and at the end of the critical section:
+
+	if (!rc)
+		usb_autopm_put_interface(intf);
+	up(&udev->dev.sem);
+
+Holding the device semaphore will block all external PM calls, and the
+usb_autopm_get_interface() will prevent any internal PM calls, even if
+it fails.  (Exercise: Why?)
+
+The rules for locking order are:
+
+	Never acquire any device semaphore while holding any PM mutex.
+
+	Never acquire udev->pm_mutex while holding the PM mutex for
+	a device that isn't a descendant of udev.
+
+In other words, PM mutexes should only be acquired going up the device
+tree, and they should be acquired only after locking all the device
+semaphores you need to hold.  These rules don't matter to drivers very
+much; they usually affect just the USB core.
+
+Still, drivers do need to be careful.  For example, many drivers use a
+private mutex to synchronize their normal I/O activities with their
+disconnect method.  Now if the driver supports autosuspend then it
+must call usb_autopm_put_interface() from somewhere -- maybe from its
+close method.  It should make the call while holding the private mutex,
+since a driver shouldn't call any of the usb_autopm_* functions for an
+interface from which it has been unbound.
+
+But the usb_autpm_* routines always acquire the device's PM mutex, and
+consequently the locking order has to be: private mutex first, PM
+mutex second.  Since the suspend method is always called with the PM
+mutex held, it mustn't try to acquire the private mutex.  It has to
+synchronize with the driver's I/O activities in some other way.
+
+
+	Interaction between dynamic PM and system PM
+	--------------------------------------------
+
+Dynamic power management and system power management can interact in
+a couple of ways.
+
+Firstly, a device may already be manually suspended or autosuspended
+when a system suspend occurs.  Since system suspends are supposed to
+be as transparent as possible, the device should remain suspended
+following the system resume.  The 2.6.23 kernel obeys this principle
+for manually suspended devices but not for autosuspended devices; they
+do get resumed when the system wakes up.  (Presumably they will be
+autosuspended again after their idle-delay time expires.)  In later
+kernels this behavior will be fixed.
+
+(There is an exception.  If a device would undergo a reset-resume
+instead of a normal resume, and the device is enabled for remote
+wakeup, then the reset-resume takes place even if the device was
+already suspended when the system suspend began.  The justification is
+that a reset-resume is a kind of remote-wakeup event.  Or to put it
+another way, a device which needs a reset won't be able to generate
+normal remote-wakeup signals, so it ought to be resumed immediately.)
+
+Secondly, a dynamic power-management event may occur as a system
+suspend is underway.  The window for this is short, since system
+suspends don't take long (a few seconds usually), but it can happen.
+For example, a suspended device may send a remote-wakeup signal while
+the system is suspending.  The remote wakeup may succeed, which would
+cause the system suspend to abort.  If the remote wakeup doesn't
+succeed, it may still remain active and thus cause the system to
+resume as soon as the system suspend is complete.  Or the remote
+wakeup may fail and get lost.  Which outcome occurs depends on timing
+and on the hardware and firmware design.
+
+More interestingly, a device might undergo a manual resume or
+autoresume during system suspend.  With current kernels this shouldn't
+happen, because manual resumes must be initiated by userspace and
+autoresumes happen in response to I/O requests, but all user processes
+and I/O should be quiescent during a system suspend -- thanks to the
+freezer.  However there are plans to do away with the freezer, which
+would mean these things would become possible.  If and when this comes
+about, the USB core will carefully arrange matters so that either type
+of resume will block until the entire system has resumed.
diff --git a/Documentation/usb/usb-serial.txt b/Documentation/usb/usb-serial.txt
index 5b635ae..4e0b62b 100644
--- a/Documentation/usb/usb-serial.txt
+++ b/Documentation/usb/usb-serial.txt
@@ -428,6 +428,17 @@
   See http://www.uuhaus.de/linux/palmconnect.html for up-to-date
   information on this driver.
 
+Winchiphead CH341 Driver
+
+  This driver is for the Winchiphead CH341 USB-RS232 Converter. This chip
+  also implements an IEEE 1284 parallel port, I2C and SPI, but that is not
+  supported by the driver. The protocol was analyzed from the behaviour
+  of the Windows driver, no datasheet is available at present.
+  The manufacturer's website: http://www.winchiphead.com/.
+  For any questions or problems with this driver, please contact
+  frank@kingswood-consulting.co.uk.
+
+
 Generic Serial driver
 
   If your device is not one of the above listed devices, compatible with
diff --git a/Documentation/usb/usbmon.txt b/Documentation/usb/usbmon.txt
index 53ae866a..2917ce4 100644
--- a/Documentation/usb/usbmon.txt
+++ b/Documentation/usb/usbmon.txt
@@ -34,9 +34,12 @@
 Verify that bus sockets are present.
 
 # ls /sys/kernel/debug/usbmon
-1s  1t  1u  2s  2t  2u  3s  3t  3u  4s  4t  4u
+0s  0t  0u  1s  1t  1u  2s  2t  2u  3s  3t  3u  4s  4t  4u
 #
 
+Now you can choose to either use the sockets numbered '0' (to capture packets on
+all buses), and skip to step #3, or find the bus used by your device with step #2.
+
 2. Find which bus connects to the desired device
 
 Run "cat /proc/bus/usb/devices", and find the T-line which corresponds to
@@ -56,6 +59,10 @@
 
 # cat /sys/kernel/debug/usbmon/3u > /tmp/1.mon.out
 
+to listen on a single bus, otherwise, to listen on all buses, type:
+
+# cat /sys/kernel/debug/usbmon/0u > /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.
diff --git a/MAINTAINERS b/MAINTAINERS
index c4eca56..60e649f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -677,6 +677,13 @@
 M:	hskinnemoen@atmel.com
 S:	Supported
 
+ATMEL USBA UDC DRIVER
+P:	Haavard Skinnemoen
+M:	hskinnemoen@atmel.com
+L:	kernel@avr32linux.org
+W:	http://avr32linux.org/twiki/bin/view/Main/AtmelUsbDeviceDriver
+S:	Supported
+
 ATMEL WIRELESS DRIVER
 P:	Simon Kelley
 M:	simon@thekelleys.org.uk
diff --git a/arch/arm/mach-imx/cpufreq.c b/arch/arm/mach-imx/cpufreq.c
index 467d899..e548ba7 100644
--- a/arch/arm/mach-imx/cpufreq.c
+++ b/arch/arm/mach-imx/cpufreq.c
@@ -269,7 +269,6 @@
 		return -EINVAL;
 
 	policy->cur = policy->min = policy->max = imx_get_speed(0);
-	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 	policy->cpuinfo.min_freq = 8000;
 	policy->cpuinfo.max_freq = 200000;
 	 /* Manual states, that PLL stabilizes in two CLK32 periods */
diff --git a/arch/arm/mach-sa1100/cpu-sa1110.c b/arch/arm/mach-sa1100/cpu-sa1110.c
index 78f4c13..36b47ff 100644
--- a/arch/arm/mach-sa1100/cpu-sa1110.c
+++ b/arch/arm/mach-sa1100/cpu-sa1110.c
@@ -331,7 +331,6 @@
 	if (policy->cpu != 0)
 		return -EINVAL;
 	policy->cur = policy->min = policy->max = sa11x0_getspeed(0);
-	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 	policy->cpuinfo.min_freq = 59000;
 	policy->cpuinfo.max_freq = 287000;
 	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c
index a0c71dc..c0d63b0 100644
--- a/arch/arm/plat-omap/cpu-omap.c
+++ b/arch/arm/plat-omap/cpu-omap.c
@@ -108,7 +108,6 @@
 	if (policy->cpu != 0)
 		return -EINVAL;
 	policy->cur = policy->min = policy->max = omap_getspeed(0);
-	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 	policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000;
 	policy->cpuinfo.max_freq = clk_round_rate(mpu_clk, VERY_HI_RATE) / 1000;
 	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
diff --git a/arch/blackfin/mach-bf533/cpu.c b/arch/blackfin/mach-bf533/cpu.c
index 6fd9cfd..b7a0e0f 100644
--- a/arch/blackfin/mach-bf533/cpu.c
+++ b/arch/blackfin/mach-bf533/cpu.c
@@ -118,8 +118,6 @@
 	if (policy->cpu != 0)
 		return -EINVAL;
 
-	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-
 	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
 	/*Now ,only support one cpu */
 	policy->cur = bf533_getfreq(0);
diff --git a/arch/blackfin/mach-bf537/boards/generic_board.c b/arch/blackfin/mach-bf537/boards/generic_board.c
index 5e9d09e..6668c8e 100644
--- a/arch/blackfin/mach-bf537/boards/generic_board.c
+++ b/arch/blackfin/mach-bf537/boards/generic_board.c
@@ -40,7 +40,7 @@
 #include <linux/pata_platform.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
-#include <linux/usb_sl811.h>
+#include <linux/usb/sl811.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
 #include <asm/reboot.h>
diff --git a/arch/blackfin/mach-bf537/boards/pnav10.c b/arch/blackfin/mach-bf537/boards/pnav10.c
index 20507e9..f83a254 100644
--- a/arch/blackfin/mach-bf537/boards/pnav10.c
+++ b/arch/blackfin/mach-bf537/boards/pnav10.c
@@ -40,7 +40,7 @@
 #include <linux/irq.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
-#include <linux/usb_sl811.h>
+#include <linux/usb/sl811.h>
 
 #include <linux/spi/ad7877.h>
 
diff --git a/arch/blackfin/mach-bf537/boards/stamp.c b/arch/blackfin/mach-bf537/boards/stamp.c
index 47d7d4a..f42ba3a 100644
--- a/arch/blackfin/mach-bf537/boards/stamp.c
+++ b/arch/blackfin/mach-bf537/boards/stamp.c
@@ -40,7 +40,7 @@
 #include <linux/pata_platform.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
-#include <linux/usb_sl811.h>
+#include <linux/usb/sl811.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
 #include <asm/reboot.h>
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig
index 515abb9..f1486f8 100644
--- a/arch/i386/Kconfig
+++ b/arch/i386/Kconfig
@@ -1211,6 +1211,16 @@
 	  processor goes idle (as is done by the scheduler).  The
 	  other workaround is idle=poll boot option.
 
+config GEODE_MFGPT_TIMER
+	bool "Geode Multi-Function General Purpose Timer (MFGPT) events"
+	depends on MGEODE_LX && GENERIC_TIME && GENERIC_CLOCKEVENTS
+	default y
+	help
+	  This driver provides a clock event source based on the MFGPT
+	  timer(s) in the CS5535 and CS5536 companion chip for the geode.
+	  MFGPTs have a better resolution and max interval than the
+	  generic PIT, and are suitable for use as high-res timers.
+
 config K8_NB
 	def_bool y
 	depends on AGP_AMD64
diff --git a/arch/ia64/kernel/cpufreq/acpi-cpufreq.c b/arch/ia64/kernel/cpufreq/acpi-cpufreq.c
index 8c6ec70..b8498ea6 100644
--- a/arch/ia64/kernel/cpufreq/acpi-cpufreq.c
+++ b/arch/ia64/kernel/cpufreq/acpi-cpufreq.c
@@ -321,8 +321,6 @@
 			    data->acpi_data.states[i].transition_latency * 1000;
 		}
 	}
-	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-
 	policy->cur = processor_get_freq(data, policy->cpu);
 
 	/* table init */
diff --git a/arch/ia64/sn/kernel/tiocx.c b/arch/ia64/sn/kernel/tiocx.c
index 5a289e4..a88eba3 100644
--- a/arch/ia64/sn/kernel/tiocx.c
+++ b/arch/ia64/sn/kernel/tiocx.c
@@ -66,8 +66,7 @@
 
 }
 
-static int tiocx_uevent(struct device *dev, char **envp, int num_envp,
-			 char *buffer, int buffer_size)
+static int tiocx_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	return -ENODEV;
 }
diff --git a/arch/powerpc/kernel/of_device.c b/arch/powerpc/kernel/of_device.c
index 89b911e..8f3db32 100644
--- a/arch/powerpc/kernel/of_device.c
+++ b/arch/powerpc/kernel/of_device.c
@@ -57,26 +57,21 @@
 	return tsize;
 }
 
-int of_device_uevent(struct device *dev,
-		char **envp, int num_envp, char *buffer, int buffer_size)
+int of_device_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct of_device *ofdev;
 	const char *compat;
-	int i = 0, length = 0, seen = 0, cplen, sl;
+	int seen = 0, cplen, sl;
 
 	if (!dev)
 		return -ENODEV;
 
 	ofdev = to_of_device(dev);
 
-	if (add_uevent_var(envp, num_envp, &i,
-			   buffer, buffer_size, &length,
-			   "OF_NAME=%s", ofdev->node->name))
+	if (add_uevent_var(env, "OF_NAME=%s", ofdev->node->name))
 		return -ENOMEM;
 
-	if (add_uevent_var(envp, num_envp, &i,
-			   buffer, buffer_size, &length,
-			   "OF_TYPE=%s", ofdev->node->type))
+	if (add_uevent_var(env, "OF_TYPE=%s", ofdev->node->type))
 		return -ENOMEM;
 
         /* Since the compatible field can contain pretty much anything
@@ -85,9 +80,7 @@
 
 	compat = of_get_property(ofdev->node, "compatible", &cplen);
 	while (compat && *compat && cplen > 0) {
-		if (add_uevent_var(envp, num_envp, &i,
-				   buffer, buffer_size, &length,
-				   "OF_COMPATIBLE_%d=%s", seen, compat))
+		if (add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat))
 			return -ENOMEM;
 
 		sl = strlen (compat) + 1;
@@ -96,25 +89,17 @@
 		seen++;
 	}
 
-	if (add_uevent_var(envp, num_envp, &i,
-			   buffer, buffer_size, &length,
-			   "OF_COMPATIBLE_N=%d", seen))
+	if (add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen))
 		return -ENOMEM;
 
 	/* modalias is trickier, we add it in 2 steps */
-	if (add_uevent_var(envp, num_envp, &i,
-			   buffer, buffer_size, &length,
-			   "MODALIAS="))
+	if (add_uevent_var(env, "MODALIAS="))
 		return -ENOMEM;
-
-	sl = of_device_get_modalias(ofdev, &buffer[length-1],
-					buffer_size-length);
-	if (sl >= (buffer_size-length))
+	sl = of_device_get_modalias(ofdev, &env->buf[env->buflen-1],
+				    sizeof(env->buf) - env->buflen);
+	if (sl >= (sizeof(env->buf) - env->buflen))
 		return -ENOMEM;
-
-	length += sl;
-
-	envp[i] = NULL;
+	env->buflen += sl;
 
 	return 0;
 }
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c
index cb22a35..19a5656 100644
--- a/arch/powerpc/kernel/vio.c
+++ b/arch/powerpc/kernel/vio.c
@@ -317,30 +317,20 @@
 	return (ids != NULL) && (vio_match_device(ids, vio_dev) != NULL);
 }
 
-static int vio_hotplug(struct device *dev, char **envp, int num_envp,
-			char *buffer, int buffer_size)
+static int vio_hotplug(struct device *dev, struct kobj_uevent_env *env)
 {
 	const struct vio_dev *vio_dev = to_vio_dev(dev);
 	struct device_node *dn;
 	const char *cp;
-	int length;
-
-	if (!num_envp)
-		return -ENOMEM;
 
 	dn = dev->archdata.of_node;
 	if (!dn)
 		return -ENODEV;
-	cp = of_get_property(dn, "compatible", &length);
+	cp = of_get_property(dn, "compatible", NULL);
 	if (!cp)
 		return -ENODEV;
 
-	envp[0] = buffer;
-	length = scnprintf(buffer, buffer_size, "MODALIAS=vio:T%sS%s",
-				vio_dev->type, cp);
-	if ((buffer_size - length) <= 0)
-		return -ENOMEM;
-	envp[1] = NULL;
+	add_uevent_var(env, "MODALIAS=vio:T%sS%s", vio_dev->type, cp);
 	return 0;
 }
 
diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq.c b/arch/powerpc/platforms/cell/cbe_cpufreq.c
index 901236f..5123e9d 100644
--- a/arch/powerpc/platforms/cell/cbe_cpufreq.c
+++ b/arch/powerpc/platforms/cell/cbe_cpufreq.c
@@ -107,8 +107,6 @@
 		pr_debug("%d: %d\n", i, cbe_freqs[i].frequency);
 	}
 
-	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-
 	/* if DEBUG is enabled set_pmode() measures the latency
 	 * of a transition */
 	policy->cpuinfo.transition_latency = 25000;
diff --git a/arch/powerpc/platforms/pasemi/cpufreq.c b/arch/powerpc/platforms/pasemi/cpufreq.c
index 3ae0838..1cfb8b0 100644
--- a/arch/powerpc/platforms/pasemi/cpufreq.c
+++ b/arch/powerpc/platforms/pasemi/cpufreq.c
@@ -195,8 +195,6 @@
 		pr_debug("%d: %d\n", i, pas_freqs[i].frequency);
 	}
 
-	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-
 	policy->cpuinfo.transition_latency = get_gizmo_latency();
 
 	cur_astate = get_cur_astate(policy->cpu);
diff --git a/arch/powerpc/platforms/powermac/cpufreq_32.c b/arch/powerpc/platforms/powermac/cpufreq_32.c
index 1fe35da..c04abcc 100644
--- a/arch/powerpc/platforms/powermac/cpufreq_32.c
+++ b/arch/powerpc/platforms/powermac/cpufreq_32.c
@@ -410,7 +410,6 @@
 	if (policy->cpu != 0)
 		return -ENODEV;
 
-	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 	policy->cpuinfo.transition_latency	= CPUFREQ_ETERNAL;
 	policy->cur = cur_freq;
 
diff --git a/arch/powerpc/platforms/powermac/cpufreq_64.c b/arch/powerpc/platforms/powermac/cpufreq_64.c
index 00f5029..4dfb4bc 100644
--- a/arch/powerpc/platforms/powermac/cpufreq_64.c
+++ b/arch/powerpc/platforms/powermac/cpufreq_64.c
@@ -357,7 +357,6 @@
 
 static int g5_cpufreq_cpu_init(struct cpufreq_policy *policy)
 {
-	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
 	policy->cur = g5_cpu_freqs[g5_query_freq()].frequency;
 	/* secondary CPUs are tied to the primary one by the
diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c
index 4bb634a..ea0b2c7 100644
--- a/arch/powerpc/platforms/ps3/system-bus.c
+++ b/arch/powerpc/platforms/ps3/system-bus.c
@@ -437,18 +437,13 @@
 	dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);
 }
 
-static int ps3_system_bus_uevent(struct device *_dev, char **envp,
-				 int num_envp, char *buffer, int buffer_size)
+static int ps3_system_bus_uevent(struct device *_dev, struct kobj_uevent_env *env)
 {
 	struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
 	int i = 0, length = 0;
 
-	if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
-			   &length, "MODALIAS=ps3:%d",
-			   dev->match_id))
+	if (add_uevent_var(env, "MODALIAS=ps3:%d", dev->match_id))
 		return -ENOMEM;
-
-	envp[i] = NULL;
 	return 0;
 }
 
diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c
index 62391fb..ac61cf4 100644
--- a/arch/s390/appldata/appldata_base.c
+++ b/arch/s390/appldata/appldata_base.c
@@ -547,8 +547,7 @@
 	spin_unlock(&appldata_timer_lock);
 }
 
-static void
-appldata_offline_cpu(int cpu)
+static void __cpuinit appldata_offline_cpu(int cpu)
 {
 	del_virt_timer(&per_cpu(appldata_timer, cpu));
 	if (atomic_dec_and_test(&appldata_expire_count)) {
@@ -560,9 +559,9 @@
 	spin_unlock(&appldata_timer_lock);
 }
 
-static int __cpuinit
-appldata_cpu_notify(struct notifier_block *self,
-		    unsigned long action, void *hcpu)
+static int __cpuinit appldata_cpu_notify(struct notifier_block *self,
+					 unsigned long action,
+					 void *hcpu)
 {
 	switch (action) {
 	case CPU_ONLINE:
@@ -608,63 +607,15 @@
 	register_hotcpu_notifier(&appldata_nb);
 
 	appldata_sysctl_header = register_sysctl_table(appldata_dir_table);
-#ifdef MODULE
-	appldata_dir_table[0].de->owner = THIS_MODULE;
-	appldata_table[0].de->owner = THIS_MODULE;
-	appldata_table[1].de->owner = THIS_MODULE;
-#endif
 
 	P_DEBUG("Base interface initialized.\n");
 	return 0;
 }
 
-/*
- * appldata_exit()
- *
- * stop timer, unregister /proc entries
- */
-static void __exit appldata_exit(void)
-{
-	struct list_head *lh;
-	struct appldata_ops *ops;
-	int rc, i;
+__initcall(appldata_init);
 
-	P_DEBUG("Unloading module ...\n");
-	/*
-	 * ops list should be empty, but just in case something went wrong...
-	 */
-	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,
-				(unsigned long) ops->data, ops->size,
-				ops->mod_lvl);
-		if (rc != 0) {
-			P_ERROR("STOP DIAG 0xDC for %s failed, "
-				"return code: %d\n", ops->name, rc);
-		}
-	}
-	spin_unlock(&appldata_ops_lock);
-
-	for_each_online_cpu(i)
-		appldata_offline_cpu(i);
-
-	appldata_timer_active = 0;
-
-	unregister_sysctl_table(appldata_sysctl_header);
-
-	destroy_workqueue(appldata_wq);
-	P_DEBUG("... module unloaded!\n");
-}
 /**************************** init / exit <END> ******************************/
 
-
-module_init(appldata_init);
-module_exit(appldata_exit);
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Gerald Schaefer");
-MODULE_DESCRIPTION("Linux-VM Monitor Stream, base infrastructure");
-
 EXPORT_SYMBOL_GPL(appldata_register_ops);
 EXPORT_SYMBOL_GPL(appldata_unregister_ops);
 EXPORT_SYMBOL_GPL(appldata_diag);
diff --git a/arch/s390/kernel/audit.c b/arch/s390/kernel/audit.c
index d1c76fe..f4932c2 100644
--- a/arch/s390/kernel/audit.c
+++ b/arch/s390/kernel/audit.c
@@ -2,6 +2,7 @@
 #include <linux/types.h>
 #include <linux/audit.h>
 #include <asm/unistd.h>
+#include "audit.h"
 
 static unsigned dir_class[] = {
 #include <asm-generic/audit_dir_write.h>
@@ -40,7 +41,6 @@
 int audit_classify_syscall(int abi, unsigned syscall)
 {
 #ifdef CONFIG_COMPAT
-	extern int s390_classify_syscall(unsigned);
 	if (abi == AUDIT_ARCH_S390)
 		return s390_classify_syscall(syscall);
 #endif
@@ -61,11 +61,6 @@
 static int __init audit_classes_init(void)
 {
 #ifdef CONFIG_COMPAT
-	extern __u32 s390_dir_class[];
-	extern __u32 s390_write_class[];
-	extern __u32 s390_read_class[];
-	extern __u32 s390_chattr_class[];
-	extern __u32 s390_signal_class[];
 	audit_register_class(AUDIT_CLASS_WRITE_32, s390_write_class);
 	audit_register_class(AUDIT_CLASS_READ_32, s390_read_class);
 	audit_register_class(AUDIT_CLASS_DIR_WRITE_32, s390_dir_class);
diff --git a/arch/s390/kernel/audit.h b/arch/s390/kernel/audit.h
new file mode 100644
index 0000000..12b56f4
--- /dev/null
+++ b/arch/s390/kernel/audit.h
@@ -0,0 +1,15 @@
+#ifndef __ARCH_S390_KERNEL_AUDIT_H
+#define __ARCH_S390_KERNEL_AUDIT_H
+
+#include <linux/types.h>
+
+#ifdef CONFIG_COMPAT
+extern int s390_classify_syscall(unsigned);
+extern __u32 s390_dir_class[];
+extern __u32 s390_write_class[];
+extern __u32 s390_read_class[];
+extern __u32 s390_chattr_class[];
+extern __u32 s390_signal_class[];
+#endif /* CONFIG_COMPAT */
+
+#endif /* __ARCH_S390_KERNEL_AUDIT_H */
diff --git a/arch/s390/kernel/compat_audit.c b/arch/s390/kernel/compat_audit.c
index 0569f51..d6487bf 100644
--- a/arch/s390/kernel/compat_audit.c
+++ b/arch/s390/kernel/compat_audit.c
@@ -1,5 +1,6 @@
 #undef __s390x__
 #include <asm/unistd.h>
+#include "audit.h"
 
 unsigned s390_dir_class[] = {
 #include <asm-generic/audit_dir_write.h>
diff --git a/arch/s390/kernel/cpcmd.c b/arch/s390/kernel/cpcmd.c
index 6c89f30..d8c1131 100644
--- a/arch/s390/kernel/cpcmd.c
+++ b/arch/s390/kernel/cpcmd.c
@@ -2,7 +2,7 @@
  *  arch/s390/kernel/cpcmd.c
  *
  *  S390 version
- *    Copyright (C) 1999,2005 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Copyright IBM Corp. 1999,2007
  *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
  *               Christian Borntraeger (cborntra@de.ibm.com),
  */
@@ -21,6 +21,49 @@
 static DEFINE_SPINLOCK(cpcmd_lock);
 static char cpcmd_buf[241];
 
+static int diag8_noresponse(int cmdlen)
+{
+	register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf;
+	register unsigned long reg3 asm ("3") = cmdlen;
+
+	asm volatile(
+#ifndef CONFIG_64BIT
+		"	diag	%1,%0,0x8\n"
+#else /* CONFIG_64BIT */
+		"	sam31\n"
+		"	diag	%1,%0,0x8\n"
+		"	sam64\n"
+#endif /* CONFIG_64BIT */
+		: "+d" (reg3) : "d" (reg2) : "cc");
+	return reg3;
+}
+
+static int diag8_response(int cmdlen, char *response, int *rlen)
+{
+	register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf;
+	register unsigned long reg3 asm ("3") = (addr_t) response;
+	register unsigned long reg4 asm ("4") = cmdlen | 0x40000000L;
+	register unsigned long reg5 asm ("5") = *rlen;
+
+	asm volatile(
+#ifndef CONFIG_64BIT
+		"	diag	%2,%0,0x8\n"
+		"	brc	8,1f\n"
+		"	ar	%1,%4\n"
+#else /* CONFIG_64BIT */
+		"	sam31\n"
+		"	diag	%2,%0,0x8\n"
+		"	sam64\n"
+		"	brc	8,1f\n"
+		"	agr	%1,%4\n"
+#endif /* CONFIG_64BIT */
+		"1:\n"
+		: "+d" (reg4), "+d" (reg5)
+		: "d" (reg2), "d" (reg3), "d" (*rlen) : "cc");
+	*rlen = reg5;
+	return reg4;
+}
+
 /*
  * __cpcmd has some restrictions over cpcmd
  *  - the response buffer must reside below 2GB (if any)
@@ -28,59 +71,27 @@
  */
 int  __cpcmd(const char *cmd, char *response, int rlen, int *response_code)
 {
-	unsigned cmdlen;
-	int return_code, return_len;
+	int cmdlen;
+	int rc;
+	int response_len;
 
 	cmdlen = strlen(cmd);
 	BUG_ON(cmdlen > 240);
 	memcpy(cpcmd_buf, cmd, cmdlen);
 	ASCEBC(cpcmd_buf, cmdlen);
 
-	if (response != NULL && rlen > 0) {
-		register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf;
-		register unsigned long reg3 asm ("3") = (addr_t) response;
-		register unsigned long reg4 asm ("4") = cmdlen | 0x40000000L;
-		register unsigned long reg5 asm ("5") = rlen;
-
+	if (response) {
 		memset(response, 0, rlen);
-		asm volatile(
-#ifndef CONFIG_64BIT
-			"	diag	%2,%0,0x8\n"
-			"	brc	8,1f\n"
-			"	ar	%1,%4\n"
-#else /* CONFIG_64BIT */
-			"	sam31\n"
-			"	diag	%2,%0,0x8\n"
-			"	sam64\n"
-			"	brc	8,1f\n"
-			"	agr	%1,%4\n"
-#endif /* CONFIG_64BIT */
-			"1:\n"
-			: "+d" (reg4), "+d" (reg5)
-			: "d" (reg2), "d" (reg3), "d" (rlen) : "cc");
-		return_code = (int) reg4;
-		return_len = (int) reg5;
-                EBCASC(response, rlen);
+		response_len = rlen;
+		rc = diag8_response(cmdlen, response, &rlen);
+		EBCASC(response, response_len);
         } else {
-		register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf;
-		register unsigned long reg3 asm ("3") = cmdlen;
-		return_len = 0;
-		asm volatile(
-#ifndef CONFIG_64BIT
-			"	diag	%1,%0,0x8\n"
-#else /* CONFIG_64BIT */
-			"	sam31\n"
-			"	diag	%1,%0,0x8\n"
-			"	sam64\n"
-#endif /* CONFIG_64BIT */
-			: "+d" (reg3) : "d" (reg2) : "cc");
-		return_code = (int) reg3;
+		rc = diag8_noresponse(cmdlen);
         }
-	if (response_code != NULL)
-		*response_code = return_code;
-	return return_len;
+	if (response_code)
+		*response_code = rc;
+	return rlen;
 }
-
 EXPORT_SYMBOL(__cpcmd);
 
 int cpcmd(const char *cmd, char *response, int rlen, int *response_code)
@@ -109,5 +120,4 @@
 	}
 	return len;
 }
-
 EXPORT_SYMBOL(cpcmd);
diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c
index 50d2235..c14a336 100644
--- a/arch/s390/kernel/dis.c
+++ b/arch/s390/kernel/dis.c
@@ -1162,6 +1162,7 @@
 	unsigned int value;
 	char separator;
 	char *ptr;
+	int i;
 
 	ptr = buffer;
 	insn = find_insn(code);
@@ -1169,7 +1170,8 @@
 		ptr += sprintf(ptr, "%.5s\t", insn->name);
 		/* Extract the operands. */
 		separator = 0;
-		for (ops = formats[insn->format] + 1; *ops != 0; ops++) {
+		for (ops = formats[insn->format] + 1, i = 0;
+		     *ops != 0 && i < 6; ops++, i++) {
 			operand = operands + *ops;
 			value = extract_operand(code, operand);
 			if ((operand->flags & OPERAND_INDEX)  && value == 0)
@@ -1241,7 +1243,6 @@
 	}
 	/* Find a starting point for the disassembly. */
 	while (start < 32) {
-		hops = 0;
 		for (i = 0, hops = 0; start + i < 32 && hops < 3; hops++) {
 			if (!find_insn(code + start + i))
 				break;
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index 8b8f136..66b5190 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -735,10 +735,10 @@
 	case REIPL_METHOD_CCW_VM:
 		reipl_get_ascii_loadparm(loadparm);
 		if (strlen(loadparm) == 0)
-			sprintf(buf, "IPL %X",
+			sprintf(buf, "IPL %X CLEAR",
 				reipl_block_ccw->ipl_info.ccw.devno);
 		else
-			sprintf(buf, "IPL %X LOADPARM '%s'",
+			sprintf(buf, "IPL %X CLEAR LOADPARM '%s'",
 				reipl_block_ccw->ipl_info.ccw.devno, loadparm);
 		__cpcmd(buf, NULL, 0, NULL);
 		break;
diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S
index b4622a3..849120e 100644
--- a/arch/s390/kernel/vmlinux.lds.S
+++ b/arch/s390/kernel/vmlinux.lds.S
@@ -2,6 +2,7 @@
  * Written by Martin Schwidefsky (schwidefsky@de.ibm.com)
  */
 
+#include <asm/page.h>
 #include <asm-generic/vmlinux.lds.h>
 
 #ifndef CONFIG_64BIT
@@ -18,121 +19,142 @@
 
 SECTIONS
 {
-  . = 0x00000000;
-  _text = .;			/* Text and read-only data */
-  .text : {
-	*(.text.head)
+	. = 0x00000000;
+	.text : {
+	_text = .;		/* Text and read-only data */
+		*(.text.head)
 	TEXT_TEXT
-	SCHED_TEXT
-	LOCK_TEXT
-	KPROBES_TEXT
-	*(.fixup)
-	*(.gnu.warning)
+		SCHED_TEXT
+		LOCK_TEXT
+		KPROBES_TEXT
+		*(.fixup)
+		*(.gnu.warning)
 	} = 0x0700
 
-  _etext = .;			/* End of text section */
+	_etext = .;		/* End of text section */
 
-  RODATA
+	RODATA
 
 #ifdef CONFIG_SHARED_KERNEL
-  . = ALIGN(1048576);		/* VM shared segments are 1MB aligned */
+	. = ALIGN(0x100000);	/* VM shared segments are 1MB aligned */
 #endif
 
-  . = ALIGN(4096);
-  _eshared = .;			/* End of shareable data */
+	. = ALIGN(PAGE_SIZE);
+	_eshared = .;		/* End of shareable data */
 
-  . = ALIGN(16);		/* Exception table */
-  __start___ex_table = .;
-  __ex_table : { *(__ex_table) }
-  __stop___ex_table = .;
-
-  NOTES
-
-  BUG_TABLE
-
-  .data : {			/* Data */
-	DATA_DATA
-	CONSTRUCTORS
+	. = ALIGN(16);		/* Exception table */
+	__ex_table : {
+		__start___ex_table = .;
+		*(__ex_table)
+		__stop___ex_table = .;
 	}
 
-  . = ALIGN(4096);
-  __nosave_begin = .;
-  .data_nosave : { *(.data.nosave) }
-  . = ALIGN(4096);
-  __nosave_end = .;
+	NOTES
+	BUG_TABLE
 
-  . = ALIGN(4096);
-  .data.page_aligned : { *(.data.idt) }
+	.data : {		/* Data */
+		DATA_DATA
+		CONSTRUCTORS
+	}
 
-  . = ALIGN(256);
-  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+	. = ALIGN(PAGE_SIZE);
+	.data_nosave : {
+	__nosave_begin = .;
+		*(.data.nosave)
+	}
+	. = ALIGN(PAGE_SIZE);
+	__nosave_end = .;
 
-  . = ALIGN(256);
-  .data.read_mostly : { *(.data.read_mostly) }
-  _edata = .;			/* End of data section */
+	. = ALIGN(PAGE_SIZE);
+	.data.page_aligned : {
+		*(.data.idt)
+	}
 
-  . = ALIGN(8192);		/* init_task */
-  .data.init_task : { *(.data.init_task) }
+	. = ALIGN(0x100);
+	.data.cacheline_aligned : {
+		*(.data.cacheline_aligned)
+	}
 
-  /* will be freed after init */
-  . = ALIGN(4096);		/* Init code and data */
-  __init_begin = .;
-  .init.text : { 
-	_sinittext = .;
-	*(.init.text)
-	_einittext = .;
-  }
-  /*
-   * .exit.text is discarded at runtime, not link time,
-   * to deal with references from __bug_table
-   */
-  .exit.text :	 { *(.exit.text) }
+	. = ALIGN(0x100);
+	.data.read_mostly : {
+		*(.data.read_mostly)
+	}
+	_edata = .;		/* End of data section */
 
-  .init.data : { *(.init.data) }
-  . = ALIGN(256);
-  __setup_start = .;
-  .init.setup : { *(.init.setup) }
-  __setup_end = .;
-  __initcall_start = .;
-  .initcall.init : {
-	INITCALLS
-  }
-  __initcall_end = .;
-  __con_initcall_start = .;
-  .con_initcall.init : { *(.con_initcall.init) }
-  __con_initcall_end = .;
-  SECURITY_INIT
+	. = ALIGN(2 * PAGE_SIZE);	/* init_task */
+	.data.init_task : {
+		*(.data.init_task)
+	}
+
+	/* will be freed after init */
+	. = ALIGN(PAGE_SIZE);	/* Init code and data */
+	__init_begin = .;
+	.init.text : {
+		_sinittext = .;
+		*(.init.text)
+		_einittext = .;
+	}
+	/*
+	 * .exit.text is discarded at runtime, not link time,
+	 * to deal with references from __bug_table
+	*/
+	.exit.text : {
+		*(.exit.text)
+	}
+
+	.init.data : {
+		*(.init.data)
+	}
+	. = ALIGN(0x100);
+	.init.setup : {
+		__setup_start = .;
+		*(.init.setup)
+		__setup_end = .;
+	}
+	.initcall.init : {
+		__initcall_start = .;
+		INITCALLS
+		__initcall_end = .;
+	}
+
+	.con_initcall.init : {
+		__con_initcall_start = .;
+		*(.con_initcall.init)
+		__con_initcall_end = .;
+	}
+	SECURITY_INIT
 
 #ifdef CONFIG_BLK_DEV_INITRD
-  . = ALIGN(256);
-  __initramfs_start = .;
-  .init.ramfs : { *(.init.initramfs) }
-  . = ALIGN(2);
-  __initramfs_end = .;
+	. = ALIGN(0x100);
+	.init.ramfs : {
+		__initramfs_start = .;
+		*(.init.ramfs)
+		. = ALIGN(2);
+		__initramfs_end = .;
+	}
 #endif
-  PERCPU(4096)
-  . = ALIGN(4096);
-  __init_end = .;
-  /* freed after init ends here */
 
-  __bss_start = .;		/* BSS */
-  .bss : { *(.bss) }
-  . = ALIGN(2);
-  __bss_stop = .;
+	PERCPU(PAGE_SIZE)
+	. = ALIGN(PAGE_SIZE);
+	__init_end = .;		/* freed after init ends here */
 
-  _end = . ;
-
-  /* Sections to be discarded */
-  /DISCARD/ : {
-	*(.exit.data) *(.exitcall.exit)
+	/* BSS */
+	.bss : {
+		__bss_start = .;
+		*(.bss)
+		. = ALIGN(2);
+		__bss_stop = .;
 	}
 
-  /* Stabs debugging sections.  */
-  .stab 0 : { *(.stab) }
-  .stabstr 0 : { *(.stabstr) }
-  .stab.excl 0 : { *(.stab.excl) }
-  .stab.exclstr 0 : { *(.stab.exclstr) }
-  .stab.index 0 : { *(.stab.index) }
-  .stab.indexstr 0 : { *(.stab.indexstr) }
-  .comment 0 : { *(.comment) }
+	_end = . ;
+
+	/* Sections to be discarded */
+	/DISCARD/ : {
+		*(.exit.data)
+		*(.exitcall.exit)
+	}
+
+	/* Debugging sections.	*/
+	STABS_DEBUG
+	DWARF_DEBUG
 }
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index 5405519..4c1ac34 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -468,7 +468,7 @@
 	__u64 refselmk;
 	__u64 refcmpmk;
 	__u64 reserved;
-} __attribute__ ((packed)) pfault_refbk_t;
+} __attribute__ ((packed, aligned(8))) pfault_refbk_t;
 
 int pfault_init(void)
 {
diff --git a/arch/sh/kernel/cpufreq.c b/arch/sh/kernel/cpufreq.c
index e618902..71d1c42 100644
--- a/arch/sh/kernel/cpufreq.c
+++ b/arch/sh/kernel/cpufreq.c
@@ -93,7 +93,6 @@
 	policy->cpuinfo.max_freq = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000;
 	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
 
-	policy->governor	= CPUFREQ_DEFAULT_GOVERNOR;
 	policy->cur		= sh_cpufreq_get(policy->cpu);
 	policy->min		= policy->cpuinfo.min_freq;
 	policy->max		= policy->cpuinfo.max_freq;
diff --git a/arch/sparc64/kernel/us2e_cpufreq.c b/arch/sparc64/kernel/us2e_cpufreq.c
index 1f83fe6..791c151 100644
--- a/arch/sparc64/kernel/us2e_cpufreq.c
+++ b/arch/sparc64/kernel/us2e_cpufreq.c
@@ -326,7 +326,6 @@
 	table[2].index = 5;
 	table[3].frequency = CPUFREQ_TABLE_END;
 
-	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 	policy->cpuinfo.transition_latency = 0;
 	policy->cur = clock_tick;
 
diff --git a/arch/x86/kernel/Makefile_32 b/arch/x86/kernel/Makefile_32
index c624193..7ff0206 100644
--- a/arch/x86/kernel/Makefile_32
+++ b/arch/x86/kernel/Makefile_32
@@ -7,7 +7,7 @@
 obj-y	:= process_32.o signal_32.o entry_32.o traps_32.o irq_32.o \
 		ptrace_32.o time_32.o ioport_32.o ldt_32.o setup_32.o i8259_32.o sys_i386_32.o \
 		pci-dma_32.o i386_ksyms_32.o i387_32.o bootflag.o e820_32.o\
-		quirks.o i8237.o topology.o alternative.o i8253_32.o tsc_32.o
+		quirks.o i8237.o topology.o alternative.o i8253.o tsc_32.o
 
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-y				+= cpu/
@@ -37,9 +37,9 @@
 obj-$(CONFIG_DOUBLEFAULT) 	+= doublefault_32.o
 obj-$(CONFIG_VM86)		+= vm86_32.o
 obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
-obj-$(CONFIG_HPET_TIMER) 	+= hpet_32.o
+obj-$(CONFIG_HPET_TIMER) 	+= hpet.o
 obj-$(CONFIG_K8_NB)		+= k8.o
-obj-$(CONFIG_MGEODE_LX)		+= geode_32.o
+obj-$(CONFIG_MGEODE_LX)		+= geode_32.o mfgpt_32.o
 
 obj-$(CONFIG_VMI)		+= vmi_32.o vmiclock_32.o
 obj-$(CONFIG_PARAVIRT)		+= paravirt_32.o
diff --git a/arch/x86/kernel/Makefile_64 b/arch/x86/kernel/Makefile_64
index 3ab017a..43da662 100644
--- a/arch/x86/kernel/Makefile_64
+++ b/arch/x86/kernel/Makefile_64
@@ -8,8 +8,8 @@
 		ptrace_64.o time_64.o ioport_64.o ldt_64.o setup_64.o i8259_64.o sys_x86_64.o \
 		x8664_ksyms_64.o i387_64.o syscall_64.o vsyscall_64.o \
 		setup64.o bootflag.o e820_64.o reboot_64.o quirks.o i8237.o \
-		pci-dma_64.o pci-nommu_64.o alternative.o hpet_64.o tsc_64.o bugs_64.o \
-		perfctr-watchdog.o
+		pci-dma_64.o pci-nommu_64.o alternative.o hpet.o tsc_64.o bugs_64.o \
+		perfctr-watchdog.o i8253.o
 
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
 obj-$(CONFIG_X86_MCE)		+= mce_64.o therm_throt.o
diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c
index 925758d..395928d 100644
--- a/arch/x86/kernel/apic_64.c
+++ b/arch/x86/kernel/apic_64.c
@@ -25,6 +25,7 @@
 #include <linux/sysdev.h>
 #include <linux/module.h>
 #include <linux/ioport.h>
+#include <linux/clockchips.h>
 
 #include <asm/atomic.h>
 #include <asm/smp.h>
@@ -39,12 +40,9 @@
 #include <asm/hpet.h>
 #include <asm/apic.h>
 
-int apic_mapped;
 int apic_verbosity;
-int apic_runs_main_timer;
-int apic_calibrate_pmtmr __initdata;
-
-int disable_apic_timer __initdata;
+int disable_apic_timer __cpuinitdata;
+static int apic_calibrate_pmtmr __initdata;
 
 /* Local APIC timer works in C2? */
 int local_apic_timer_c2_ok;
@@ -56,14 +54,78 @@
 	.flags = IORESOURCE_MEM | IORESOURCE_BUSY,
 };
 
-/*
- * cpu_mask that denotes the CPUs that needs timer interrupt coming in as
- * IPIs in place of local APIC timers
- */
-static cpumask_t timer_interrupt_broadcast_ipi_mask;
+static unsigned int calibration_result;
 
-/* Using APIC to generate smp_local_timer_interrupt? */
-int using_apic_timer __read_mostly = 0;
+static int lapic_next_event(unsigned long delta,
+			    struct clock_event_device *evt);
+static void lapic_timer_setup(enum clock_event_mode mode,
+			      struct clock_event_device *evt);
+
+static void lapic_timer_broadcast(cpumask_t mask);
+
+static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen);
+
+static struct clock_event_device lapic_clockevent = {
+	.name		= "lapic",
+	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT
+			| CLOCK_EVT_FEAT_C3STOP | CLOCK_EVT_FEAT_DUMMY,
+	.shift		= 32,
+	.set_mode	= lapic_timer_setup,
+	.set_next_event	= lapic_next_event,
+	.broadcast	= lapic_timer_broadcast,
+	.rating		= 100,
+	.irq		= -1,
+};
+static DEFINE_PER_CPU(struct clock_event_device, lapic_events);
+
+static int lapic_next_event(unsigned long delta,
+			    struct clock_event_device *evt)
+{
+	apic_write(APIC_TMICT, delta);
+	return 0;
+}
+
+static void lapic_timer_setup(enum clock_event_mode mode,
+			      struct clock_event_device *evt)
+{
+	unsigned long flags;
+	unsigned int v;
+
+	/* Lapic used as dummy for broadcast ? */
+	if (evt->features & CLOCK_EVT_FEAT_DUMMY)
+		return;
+
+	local_irq_save(flags);
+
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+	case CLOCK_EVT_MODE_ONESHOT:
+		__setup_APIC_LVTT(calibration_result,
+				  mode != CLOCK_EVT_MODE_PERIODIC, 1);
+		break;
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+		v = apic_read(APIC_LVTT);
+		v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
+		apic_write(APIC_LVTT, v);
+		break;
+	case CLOCK_EVT_MODE_RESUME:
+		/* Nothing to do here */
+		break;
+	}
+
+	local_irq_restore(flags);
+}
+
+/*
+ * Local APIC timer broadcast function
+ */
+static void lapic_timer_broadcast(cpumask_t mask)
+{
+#ifdef CONFIG_SMP
+	send_IPI_mask(mask, LOCAL_TIMER_VECTOR);
+#endif
+}
 
 static void apic_pm_activate(void);
 
@@ -184,7 +246,10 @@
 	apic_write(APIC_SPIV, value);
 
 	if (!virt_wire_setup) {
-		/* For LVT0 make it edge triggered, active high, external and enabled */
+		/*
+		 * For LVT0 make it edge triggered, active high,
+		 * external and enabled
+		 */
 		value = apic_read(APIC_LVT0);
 		value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING |
 			APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR |
@@ -420,10 +485,12 @@
 	value = apic_read(APIC_LVT0) & APIC_LVT_MASKED;
 	if (!smp_processor_id() && !value) {
 		value = APIC_DM_EXTINT;
-		apic_printk(APIC_VERBOSE, "enabled ExtINT on CPU#%d\n", smp_processor_id());
+		apic_printk(APIC_VERBOSE, "enabled ExtINT on CPU#%d\n",
+			    smp_processor_id());
 	} else {
 		value = APIC_DM_EXTINT | APIC_LVT_MASKED;
-		apic_printk(APIC_VERBOSE, "masked ExtINT on CPU#%d\n", smp_processor_id());
+		apic_printk(APIC_VERBOSE, "masked ExtINT on CPU#%d\n",
+			    smp_processor_id());
 	}
 	apic_write(APIC_LVT0, value);
 
@@ -706,8 +773,8 @@
 		apic_phys = mp_lapic_addr;
 
 	set_fixmap_nocache(FIX_APIC_BASE, apic_phys);
-	apic_mapped = 1;
-	apic_printk(APIC_VERBOSE,"mapped APIC to %16lx (%16lx)\n", APIC_BASE, apic_phys);
+	apic_printk(APIC_VERBOSE, "mapped APIC to %16lx (%16lx)\n",
+				APIC_BASE, apic_phys);
 
 	/* Put local APIC into the resource map. */
 	lapic_resource.start = apic_phys;
@@ -730,12 +797,14 @@
 			if (smp_found_config) {
 				ioapic_phys = mp_ioapics[i].mpc_apicaddr;
 			} else {
-				ioapic_phys = (unsigned long) alloc_bootmem_pages(PAGE_SIZE);
+				ioapic_phys = (unsigned long)
+					alloc_bootmem_pages(PAGE_SIZE);
 				ioapic_phys = __pa(ioapic_phys);
 			}
 			set_fixmap_nocache(idx, ioapic_phys);
-			apic_printk(APIC_VERBOSE,"mapped IOAPIC to %016lx (%016lx)\n",
-					__fix_to_virt(idx), ioapic_phys);
+			apic_printk(APIC_VERBOSE,
+				    "mapped IOAPIC to %016lx (%016lx)\n",
+				    __fix_to_virt(idx), ioapic_phys);
 			idx++;
 
 			if (ioapic_res != NULL) {
@@ -758,16 +827,14 @@
  * P5 APIC double write bug.
  */
 
-#define APIC_DIVISOR 16
-
-static void __setup_APIC_LVTT(unsigned int clocks)
+static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen)
 {
 	unsigned int lvtt_value, tmp_value;
-	int cpu = smp_processor_id();
 
-	lvtt_value = APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR;
-
-	if (cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask))
+	lvtt_value = LOCAL_TIMER_VECTOR;
+	if (!oneshot)
+		lvtt_value |= APIC_LVT_TIMER_PERIODIC;
+	if (!irqen)
 		lvtt_value |= APIC_LVT_MASKED;
 
 	apic_write(APIC_LVTT, lvtt_value);
@@ -780,44 +847,18 @@
 				& ~(APIC_TDR_DIV_1 | APIC_TDR_DIV_TMBASE))
 				| APIC_TDR_DIV_16);
 
-	apic_write(APIC_TMICT, clocks/APIC_DIVISOR);
+	if (!oneshot)
+		apic_write(APIC_TMICT, clocks);
 }
 
-static void setup_APIC_timer(unsigned int clocks)
+static void setup_APIC_timer(void)
 {
-	unsigned long flags;
+	struct clock_event_device *levt = &__get_cpu_var(lapic_events);
 
-	local_irq_save(flags);
+	memcpy(levt, &lapic_clockevent, sizeof(*levt));
+	levt->cpumask = cpumask_of_cpu(smp_processor_id());
 
-	/* wait for irq slice */
-	if (hpet_address && hpet_use_timer) {
-		u32 trigger = hpet_readl(HPET_T0_CMP);
-		while (hpet_readl(HPET_T0_CMP) == trigger)
-			/* do nothing */ ;
-	} else {
-		int c1, c2;
-		outb_p(0x00, 0x43);
-		c2 = inb_p(0x40);
-		c2 |= inb_p(0x40) << 8;
-		do {
-			c1 = c2;
-			outb_p(0x00, 0x43);
-			c2 = inb_p(0x40);
-			c2 |= inb_p(0x40) << 8;
-		} while (c2 - c1 < 300);
-	}
-	__setup_APIC_LVTT(clocks);
-	/* Turn off PIT interrupt if we use APIC timer as main timer.
-	   Only works with the PM timer right now
-	   TBD fix it for HPET too. */
-	if ((pmtmr_ioport != 0) &&
-		smp_processor_id() == boot_cpu_id &&
-		apic_runs_main_timer == 1 &&
-		!cpu_isset(boot_cpu_id, timer_interrupt_broadcast_ipi_mask)) {
-		stop_timer_interrupt();
-		apic_runs_main_timer++;
-	}
-	local_irq_restore(flags);
+	clockevents_register_device(levt);
 }
 
 /*
@@ -835,17 +876,22 @@
 
 #define TICK_COUNT 100000000
 
-static int __init calibrate_APIC_clock(void)
+static void __init calibrate_APIC_clock(void)
 {
 	unsigned apic, apic_start;
 	unsigned long tsc, tsc_start;
 	int result;
+
+	local_irq_disable();
+
 	/*
 	 * Put whatever arbitrary (but long enough) timeout
 	 * value into the APIC clock, we just want to get the
 	 * counter running for calibration.
+	 *
+	 * No interrupt enable !
 	 */
-	__setup_APIC_LVTT(4000000000);
+	__setup_APIC_LVTT(250000000, 0, 0);
 
 	apic_start = apic_read(APIC_TMCCT);
 #ifdef CONFIG_X86_PM_TIMER
@@ -867,123 +913,62 @@
 		result = (apic_start - apic) * 1000L * tsc_khz /
 					(tsc - tsc_start);
 	}
-	printk("result %d\n", result);
 
+	local_irq_enable();
+
+	printk(KERN_DEBUG "APIC timer calibration result %d\n", result);
 
 	printk(KERN_INFO "Detected %d.%03d MHz APIC timer.\n",
 		result / 1000 / 1000, result / 1000 % 1000);
 
-	return result * APIC_DIVISOR / HZ;
-}
+	/* Calculate the scaled math multiplication factor */
+	lapic_clockevent.mult = div_sc(result, NSEC_PER_SEC, 32);
+	lapic_clockevent.max_delta_ns =
+		clockevent_delta2ns(0x7FFFFF, &lapic_clockevent);
+	lapic_clockevent.min_delta_ns =
+		clockevent_delta2ns(0xF, &lapic_clockevent);
 
-static unsigned int calibration_result;
+	calibration_result = result / HZ;
+}
 
 void __init setup_boot_APIC_clock (void)
 {
+	/*
+	 * The local apic timer can be disabled via the kernel commandline.
+	 * Register the lapic timer as a dummy clock event source on SMP
+	 * systems, so the broadcast mechanism is used. On UP systems simply
+	 * ignore it.
+	 */
 	if (disable_apic_timer) {
 		printk(KERN_INFO "Disabling APIC timer\n");
+		/* No broadcast on UP ! */
+		if (num_possible_cpus() > 1)
+			setup_APIC_timer();
 		return;
 	}
 
 	printk(KERN_INFO "Using local APIC timer interrupts.\n");
-	using_apic_timer = 1;
+	calibrate_APIC_clock();
 
-	local_irq_disable();
-
-	calibration_result = calibrate_APIC_clock();
 	/*
-	 * Now set up the timer for real.
+	 * If nmi_watchdog is set to IO_APIC, we need the
+	 * PIT/HPET going.  Otherwise register lapic as a dummy
+	 * device.
 	 */
-	setup_APIC_timer(calibration_result);
+	if (nmi_watchdog != NMI_IO_APIC)
+		lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY;
+	else
+		printk(KERN_WARNING "APIC timer registered as dummy,"
+		       " due to nmi_watchdog=1!\n");
 
-	local_irq_enable();
+	setup_APIC_timer();
 }
 
 void __cpuinit setup_secondary_APIC_clock(void)
 {
-	local_irq_disable(); /* FIXME: Do we need this? --RR */
-	setup_APIC_timer(calibration_result);
-	local_irq_enable();
+	setup_APIC_timer();
 }
 
-void disable_APIC_timer(void)
-{
-	if (using_apic_timer) {
-		unsigned long v;
-
-		v = apic_read(APIC_LVTT);
-		/*
-		 * When an illegal vector value (0-15) is written to an LVT
-		 * entry and delivery mode is Fixed, the APIC may signal an
-		 * illegal vector error, with out regard to whether the mask
-		 * bit is set or whether an interrupt is actually seen on input.
-		 *
-		 * Boot sequence might call this function when the LVTT has
-		 * '0' vector value. So make sure vector field is set to
-		 * valid value.
-		 */
-		v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
-		apic_write(APIC_LVTT, v);
-	}
-}
-
-void enable_APIC_timer(void)
-{
-	int cpu = smp_processor_id();
-
-	if (using_apic_timer &&
-	    !cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) {
-		unsigned long v;
-
-		v = apic_read(APIC_LVTT);
-		apic_write(APIC_LVTT, v & ~APIC_LVT_MASKED);
-	}
-}
-
-void switch_APIC_timer_to_ipi(void *cpumask)
-{
-	cpumask_t mask = *(cpumask_t *)cpumask;
-	int cpu = smp_processor_id();
-
-	if (cpu_isset(cpu, mask) &&
-	    !cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) {
-		disable_APIC_timer();
-		cpu_set(cpu, timer_interrupt_broadcast_ipi_mask);
-	}
-}
-EXPORT_SYMBOL(switch_APIC_timer_to_ipi);
-
-void smp_send_timer_broadcast_ipi(void)
-{
-	int cpu = smp_processor_id();
-	cpumask_t mask;
-
-	cpus_and(mask, cpu_online_map, timer_interrupt_broadcast_ipi_mask);
-
-	if (cpu_isset(cpu, mask)) {
-		cpu_clear(cpu, mask);
-		add_pda(apic_timer_irqs, 1);
-		smp_local_timer_interrupt();
-	}
-
-	if (!cpus_empty(mask)) {
-		send_IPI_mask(mask, LOCAL_TIMER_VECTOR);
-	}
-}
-
-void switch_ipi_to_APIC_timer(void *cpumask)
-{
-	cpumask_t mask = *(cpumask_t *)cpumask;
-	int cpu = smp_processor_id();
-
-	if (cpu_isset(cpu, mask) &&
-	    cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask)) {
-		cpu_clear(cpu, timer_interrupt_broadcast_ipi_mask);
-		enable_APIC_timer();
-	}
-}
-EXPORT_SYMBOL(switch_ipi_to_APIC_timer);
-
 int setup_profiling_timer(unsigned int multiplier)
 {
 	return -EINVAL;
@@ -997,8 +982,6 @@
 	apic_write(reg, v);
 }
 
-#undef APIC_DIVISOR
-
 /*
  * Local timer interrupt handler. It does both profiling and
  * process statistics/rescheduling.
@@ -1011,22 +994,34 @@
 
 void smp_local_timer_interrupt(void)
 {
-	profile_tick(CPU_PROFILING);
-#ifdef CONFIG_SMP
-	update_process_times(user_mode(get_irq_regs()));
-#endif
-	if (apic_runs_main_timer > 1 && smp_processor_id() == boot_cpu_id)
-		main_timer_handler();
+	int cpu = smp_processor_id();
+	struct clock_event_device *evt = &per_cpu(lapic_events, cpu);
+
 	/*
-	 * We take the 'long' return path, and there every subsystem
-	 * grabs the appropriate locks (kernel lock/ irq lock).
+	 * Normally we should not be here till LAPIC has been initialized but
+	 * in some cases like kdump, its possible that there is a pending LAPIC
+	 * timer interrupt from previous kernel's context and is delivered in
+	 * new kernel the moment interrupts are enabled.
 	 *
-	 * We might want to decouple profiling from the 'long path',
-	 * and do the profiling totally in assembly.
-	 *
-	 * Currently this isn't too much of an issue (performance wise),
-	 * we can take more than 100K local irqs per second on a 100 MHz P5.
+	 * Interrupts are enabled early and LAPIC is setup much later, hence
+	 * its possible that when we get here evt->event_handler is NULL.
+	 * Check for event_handler being NULL and discard the interrupt as
+	 * spurious.
 	 */
+	if (!evt->event_handler) {
+		printk(KERN_WARNING
+		       "Spurious LAPIC timer interrupt on cpu %d\n", cpu);
+		/* Switch it off */
+		lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, evt);
+		return;
+	}
+
+	/*
+	 * the NMI deadlock-detector uses this.
+	 */
+	add_pda(apic_timer_irqs, 1);
+
+	evt->event_handler(evt);
 }
 
 /*
@@ -1042,11 +1037,6 @@
 	struct pt_regs *old_regs = set_irq_regs(regs);
 
 	/*
-	 * the NMI deadlock-detector uses this.
-	 */
-	add_pda(apic_timer_irqs, 1);
-
-	/*
 	 * NOTE! We'd better ACK the irq immediately,
 	 * because timer handling can be slow.
 	 */
@@ -1225,29 +1215,13 @@
 	disable_apic_timer = 1;
 	return 1;
 }
-
-static __init int setup_apicmaintimer(char *str)
-{
-	apic_runs_main_timer = 1;
-	nohpet = 1;
-	return 1;
-}
-__setup("apicmaintimer", setup_apicmaintimer);
-
-static __init int setup_noapicmaintimer(char *str)
-{
-	apic_runs_main_timer = -1;
-	return 1;
-}
-__setup("noapicmaintimer", setup_noapicmaintimer);
+__setup("noapictimer", setup_noapictimer);
 
 static __init int setup_apicpmtimer(char *s)
 {
 	apic_calibrate_pmtmr = 1;
 	notsc_setup(NULL);
-	return setup_apicmaintimer(NULL);
+	return 0;
 }
 __setup("apicpmtimer", setup_apicpmtimer);
 
-__setup("noapictimer", setup_noapictimer);
-
diff --git a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
index b6434a7e..ffd01e5 100644
--- a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
+++ b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
@@ -646,7 +646,6 @@
 			policy->cpuinfo.transition_latency =
 			    perf->states[i].transition_latency * 1000;
 	}
-	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 
 	data->max_freq = perf->states[0].core_frequency * 1000;
 	/* table init */
diff --git a/arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c b/arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c
index 66acd50..32f0bda 100644
--- a/arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c
+++ b/arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c
@@ -363,7 +363,6 @@
 	policy->cur = nforce2_get(policy->cpu);
 	policy->min = policy->cpuinfo.min_freq;
 	policy->max = policy->cpuinfo.max_freq;
-	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 
 	return 0;
 }
diff --git a/arch/x86/kernel/cpu/cpufreq/e_powersaver.c b/arch/x86/kernel/cpu/cpufreq/e_powersaver.c
index f43d98e..c11baaf 100644
--- a/arch/x86/kernel/cpu/cpufreq/e_powersaver.c
+++ b/arch/x86/kernel/cpu/cpufreq/e_powersaver.c
@@ -253,7 +253,6 @@
 		f_table[k].frequency = CPUFREQ_TABLE_END;
 	}
 
-	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 	policy->cpuinfo.transition_latency = 140000; /* 844mV -> 700mV in ns */
 	policy->cur = fsb * current_multiplier;
 
diff --git a/arch/x86/kernel/cpu/cpufreq/elanfreq.c b/arch/x86/kernel/cpu/cpufreq/elanfreq.c
index f317276..1e7ae7d 100644
--- a/arch/x86/kernel/cpu/cpufreq/elanfreq.c
+++ b/arch/x86/kernel/cpu/cpufreq/elanfreq.c
@@ -219,7 +219,6 @@
 	}
 
 	/* cpuinfo and default policy values */
-	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
 	policy->cur = elanfreq_get_cpu_frequency(0);
 
diff --git a/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c b/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c
index 461dabc..ed2bda1 100644
--- a/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c
+++ b/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c
@@ -420,7 +420,6 @@
 		policy->min = maxfreq / POLICY_MIN_DIV;
 	policy->max = maxfreq;
 	policy->cur = curfreq;
-	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 	policy->cpuinfo.min_freq = maxfreq / max_duration;
 	policy->cpuinfo.max_freq = maxfreq;
 	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
diff --git a/arch/x86/kernel/cpu/cpufreq/longhaul.c b/arch/x86/kernel/cpu/cpufreq/longhaul.c
index f0cce3c..5045f5d 100644
--- a/arch/x86/kernel/cpu/cpufreq/longhaul.c
+++ b/arch/x86/kernel/cpu/cpufreq/longhaul.c
@@ -710,6 +710,10 @@
 	reg = 0x78;
 	dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0,
 			     NULL);
+	/* Find PM133/VT8605 host bridge */
+	if (dev == NULL)
+		dev = pci_get_device(PCI_VENDOR_ID_VIA,
+				     PCI_DEVICE_ID_VIA_8605_0, NULL);
 	/* Find CLE266 host bridge */
 	if (dev == NULL) {
 		reg = 0x76;
@@ -918,7 +922,6 @@
 	if ((longhaul_version != TYPE_LONGHAUL_V1) && (scale_voltage != 0))
 		longhaul_setup_voltagescaling();
 
-	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 	policy->cpuinfo.transition_latency = 200000;	/* nsec */
 	policy->cur = calc_speed(longhaul_get_cpu_mult());
 
diff --git a/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c b/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c
index 4c76b51..8eb414b 100644
--- a/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c
+++ b/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c
@@ -229,7 +229,6 @@
 	cpufreq_frequency_table_get_attr(p4clockmod_table, policy->cpu);
 
 	/* cpuinfo and default policy values */
-	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 	policy->cpuinfo.transition_latency = 1000000; /* assumed */
 	policy->cur = stock_freq;
 
diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k6.c b/arch/x86/kernel/cpu/cpufreq/powernow-k6.c
index f895240..6d02853 100644
--- a/arch/x86/kernel/cpu/cpufreq/powernow-k6.c
+++ b/arch/x86/kernel/cpu/cpufreq/powernow-k6.c
@@ -160,7 +160,6 @@
 	}
 
 	/* cpuinfo and default policy values */
-	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
 	policy->cur = busfreq * max_multiplier;
 
diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k7.c b/arch/x86/kernel/cpu/cpufreq/powernow-k7.c
index ca3e1d3..7decd6a 100644
--- a/arch/x86/kernel/cpu/cpufreq/powernow-k7.c
+++ b/arch/x86/kernel/cpu/cpufreq/powernow-k7.c
@@ -637,8 +637,6 @@
 	printk (KERN_INFO PFX "Minimum speed %d MHz. Maximum speed %d MHz.\n",
 				minimum_speed/1000, maximum_speed/1000);
 
-	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-
 	policy->cpuinfo.transition_latency = cpufreq_scale(2000000UL, fsb, latency);
 
 	policy->cur = powernow_get(0);
diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
index 34ed53a..b273b69 100644
--- a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
+++ b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
@@ -76,7 +76,10 @@
 /* Return a frequency in MHz, given an input fid and did */
 static u32 find_freq_from_fiddid(u32 fid, u32 did)
 {
-	return 100 * (fid + 0x10) >> did;
+	if (current_cpu_data.x86 == 0x10)
+		return 100 * (fid + 0x10) >> did;
+	else
+		return 100 * (fid + 0x8) >> did;
 }
 
 static u32 find_khz_freq_from_fiddid(u32 fid, u32 did)
@@ -1208,7 +1211,6 @@
 	/* run on any CPU again */
 	set_cpus_allowed(current, oldmask);
 
-	pol->governor = CPUFREQ_DEFAULT_GOVERNOR;
 	if (cpu_family == CPU_HW_PSTATE)
 		pol->cpus = cpumask_of_cpu(pol->cpu);
 	else
@@ -1325,21 +1327,16 @@
 static int __cpuinit powernowk8_init(void)
 {
 	unsigned int i, supported_cpus = 0;
-	unsigned int booted_cores = 1;
 
 	for_each_online_cpu(i) {
 		if (check_supported_cpu(i))
 			supported_cpus++;
 	}
 
-#ifdef CONFIG_SMP
-	booted_cores = cpu_data[0].booted_cores;
-#endif
-
 	if (supported_cpus == num_online_cpus()) {
 		printk(KERN_INFO PFX "Found %d %s "
 			"processors (%d cpu cores) (" VERSION ")\n",
-			supported_cpus/booted_cores,
+			num_online_nodes(),
 			boot_cpu_data.x86_model_id, supported_cpus);
 		return cpufreq_register_driver(&cpufreq_amd64_driver);
 	}
diff --git a/arch/x86/kernel/cpu/cpufreq/sc520_freq.c b/arch/x86/kernel/cpu/cpufreq/sc520_freq.c
index b8fb4b5..d9f3e90 100644
--- a/arch/x86/kernel/cpu/cpufreq/sc520_freq.c
+++ b/arch/x86/kernel/cpu/cpufreq/sc520_freq.c
@@ -111,7 +111,6 @@
 		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);
 
diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c
index 6c5dc2c..811d474 100644
--- a/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c
+++ b/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c
@@ -393,7 +393,6 @@
 
 	freq = get_cur_freq(policy->cpu);
 
-	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 	policy->cpuinfo.transition_latency = 10000; /* 10uS transition latency */
 	policy->cur = freq;
 
diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c b/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c
index a5b2346..36685e8 100644
--- a/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c
+++ b/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c
@@ -348,7 +348,6 @@
 		(speed / 1000));
 
 	/* cpuinfo and default policy values */
-	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 	policy->cur = speed;
 
 	result = cpufreq_frequency_table_cpuinfo(policy, speedstep_freqs);
diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-smi.c b/arch/x86/kernel/cpu/cpufreq/speedstep-smi.c
index e1c509a..f2b5a62 100644
--- a/arch/x86/kernel/cpu/cpufreq/speedstep-smi.c
+++ b/arch/x86/kernel/cpu/cpufreq/speedstep-smi.c
@@ -290,7 +290,6 @@
 		(speed / 1000));
 
 	/* cpuinfo and default policy values */
-	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 	policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
 	policy->cur = speed;
 
diff --git a/arch/x86/kernel/geode_32.c b/arch/x86/kernel/geode_32.c
index 41e8aec..f12d8c5 100644
--- a/arch/x86/kernel/geode_32.c
+++ b/arch/x86/kernel/geode_32.c
@@ -145,10 +145,14 @@
 
 static int __init geode_southbridge_init(void)
 {
+	int timers;
+
 	if (!is_geode())
 		return -ENODEV;
 
 	init_lbars();
+	timers = geode_mfgpt_detect();
+	printk(KERN_INFO "geode:  %d MFGPT timers available.\n", timers);
 	return 0;
 }
 
diff --git a/arch/x86/kernel/hpet_32.c b/arch/x86/kernel/hpet.c
similarity index 81%
rename from arch/x86/kernel/hpet_32.c
rename to arch/x86/kernel/hpet.c
index 533d493..f836707 100644
--- a/arch/x86/kernel/hpet_32.c
+++ b/arch/x86/kernel/hpet.c
@@ -1,5 +1,6 @@
 #include <linux/clocksource.h>
 #include <linux/clockchips.h>
+#include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/hpet.h>
 #include <linux/init.h>
@@ -7,11 +8,11 @@
 #include <linux/pm.h>
 #include <linux/delay.h>
 
+#include <asm/fixmap.h>
 #include <asm/hpet.h>
+#include <asm/i8253.h>
 #include <asm/io.h>
 
-extern struct clock_event_device *global_clock_event;
-
 #define HPET_MASK	CLOCKSOURCE_MASK(32)
 #define HPET_SHIFT	22
 
@@ -22,9 +23,9 @@
  * HPET address is set in acpi/boot.c, when an ACPI entry exists
  */
 unsigned long hpet_address;
-static void __iomem * hpet_virt_address;
+static void __iomem *hpet_virt_address;
 
-static inline unsigned long hpet_readl(unsigned long a)
+unsigned long hpet_readl(unsigned long a)
 {
 	return readl(hpet_virt_address + a);
 }
@@ -34,6 +35,36 @@
 	writel(d, hpet_virt_address + a);
 }
 
+#ifdef CONFIG_X86_64
+
+#include <asm/pgtable.h>
+
+static inline void hpet_set_mapping(void)
+{
+	set_fixmap_nocache(FIX_HPET_BASE, hpet_address);
+	__set_fixmap(VSYSCALL_HPET, hpet_address, PAGE_KERNEL_VSYSCALL_NOCACHE);
+	hpet_virt_address = (void __iomem *)fix_to_virt(FIX_HPET_BASE);
+}
+
+static inline void hpet_clear_mapping(void)
+{
+	hpet_virt_address = NULL;
+}
+
+#else
+
+static inline void hpet_set_mapping(void)
+{
+	hpet_virt_address = ioremap_nocache(hpet_address, HPET_MMAP_SIZE);
+}
+
+static inline void hpet_clear_mapping(void)
+{
+	iounmap(hpet_virt_address);
+	hpet_virt_address = NULL;
+}
+#endif
+
 /*
  * HPET command line enable / disable
  */
@@ -49,6 +80,13 @@
 }
 __setup("hpet=", hpet_setup);
 
+static int __init disable_hpet(char *str)
+{
+	boot_hpet_disable = 1;
+	return 1;
+}
+__setup("nohpet", disable_hpet);
+
 static inline int is_hpet_capable(void)
 {
 	return (!boot_hpet_disable && hpet_address);
@@ -83,7 +121,7 @@
 
 	memset(&hd, 0, sizeof (hd));
 	hd.hd_phys_address = hpet_address;
-	hd.hd_address = hpet_virt_address;
+	hd.hd_address = hpet;
 	hd.hd_nirqs = nrtimers;
 	hd.hd_flags = HPET_DATA_PLATFORM;
 	hpet_reserve_timer(&hd, 0);
@@ -111,9 +149,9 @@
  */
 static unsigned long hpet_period;
 
-static void hpet_set_mode(enum clock_event_mode mode,
+static void hpet_legacy_set_mode(enum clock_event_mode mode,
 			  struct clock_event_device *evt);
-static int hpet_next_event(unsigned long delta,
+static int hpet_legacy_next_event(unsigned long delta,
 			   struct clock_event_device *evt);
 
 /*
@@ -122,10 +160,11 @@
 static struct clock_event_device hpet_clockevent = {
 	.name		= "hpet",
 	.features	= CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
-	.set_mode	= hpet_set_mode,
-	.set_next_event = hpet_next_event,
+	.set_mode	= hpet_legacy_set_mode,
+	.set_next_event = hpet_legacy_next_event,
 	.shift		= 32,
 	.irq		= 0,
+	.rating		= 50,
 };
 
 static void hpet_start_counter(void)
@@ -140,7 +179,18 @@
 	hpet_writel(cfg, HPET_CFG);
 }
 
-static void hpet_enable_int(void)
+static void hpet_resume_device(void)
+{
+	force_hpet_resume();
+}
+
+static void hpet_restart_counter(void)
+{
+	hpet_resume_device();
+	hpet_start_counter();
+}
+
+static void hpet_enable_legacy_int(void)
 {
 	unsigned long cfg = hpet_readl(HPET_CFG);
 
@@ -149,7 +199,39 @@
 	hpet_legacy_int_enabled = 1;
 }
 
-static void hpet_set_mode(enum clock_event_mode mode,
+static void hpet_legacy_clockevent_register(void)
+{
+	uint64_t hpet_freq;
+
+	/* Start HPET legacy interrupts */
+	hpet_enable_legacy_int();
+
+	/*
+	 * The period is a femto seconds value. We need to calculate the
+	 * scaled math multiplication factor for nanosecond to hpet tick
+	 * conversion.
+	 */
+	hpet_freq = 1000000000000000ULL;
+	do_div(hpet_freq, hpet_period);
+	hpet_clockevent.mult = div_sc((unsigned long) hpet_freq,
+				      NSEC_PER_SEC, 32);
+	/* Calculate the min / max delta */
+	hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF,
+							   &hpet_clockevent);
+	hpet_clockevent.min_delta_ns = clockevent_delta2ns(0x30,
+							   &hpet_clockevent);
+
+	/*
+	 * Start hpet with the boot cpu mask and make it
+	 * global after the IO_APIC has been initialized.
+	 */
+	hpet_clockevent.cpumask = cpumask_of_cpu(smp_processor_id());
+	clockevents_register_device(&hpet_clockevent);
+	global_clock_event = &hpet_clockevent;
+	printk(KERN_DEBUG "hpet clockevent registered\n");
+}
+
+static void hpet_legacy_set_mode(enum clock_event_mode mode,
 			  struct clock_event_device *evt)
 {
 	unsigned long cfg, cmp, now;
@@ -190,12 +272,12 @@
 		break;
 
 	case CLOCK_EVT_MODE_RESUME:
-		hpet_enable_int();
+		hpet_enable_legacy_int();
 		break;
 	}
 }
 
-static int hpet_next_event(unsigned long delta,
+static int hpet_legacy_next_event(unsigned long delta,
 			   struct clock_event_device *evt)
 {
 	unsigned long cnt;
@@ -215,6 +297,13 @@
 	return (cycle_t)hpet_readl(HPET_COUNTER);
 }
 
+#ifdef CONFIG_X86_64
+static cycle_t __vsyscall_fn vread_hpet(void)
+{
+	return readl((const void __iomem *)fix_to_virt(VSYSCALL_HPET) + 0xf0);
+}
+#endif
+
 static struct clocksource clocksource_hpet = {
 	.name		= "hpet",
 	.rating		= 250,
@@ -222,61 +311,17 @@
 	.mask		= HPET_MASK,
 	.shift		= HPET_SHIFT,
 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
-	.resume		= hpet_start_counter,
+	.resume		= hpet_restart_counter,
+#ifdef CONFIG_X86_64
+	.vread		= vread_hpet,
+#endif
 };
 
-/*
- * Try to setup the HPET timer
- */
-int __init hpet_enable(void)
+static int hpet_clocksource_register(void)
 {
-	unsigned long id;
-	uint64_t hpet_freq;
 	u64 tmp, start, now;
 	cycle_t t1;
 
-	if (!is_hpet_capable())
-		return 0;
-
-	hpet_virt_address = ioremap_nocache(hpet_address, HPET_MMAP_SIZE);
-
-	/*
-	 * Read the period and check for a sane value:
-	 */
-	hpet_period = hpet_readl(HPET_PERIOD);
-	if (hpet_period < HPET_MIN_PERIOD || hpet_period > HPET_MAX_PERIOD)
-		goto out_nohpet;
-
-	/*
-	 * The period is a femto seconds value. We need to calculate the
-	 * scaled math multiplication factor for nanosecond to hpet tick
-	 * conversion.
-	 */
-	hpet_freq = 1000000000000000ULL;
-	do_div(hpet_freq, hpet_period);
-	hpet_clockevent.mult = div_sc((unsigned long) hpet_freq,
-				      NSEC_PER_SEC, 32);
-	/* Calculate the min / max delta */
-	hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF,
-							   &hpet_clockevent);
-	hpet_clockevent.min_delta_ns = clockevent_delta2ns(0x30,
-							   &hpet_clockevent);
-
-	/*
-	 * Read the HPET ID register to retrieve the IRQ routing
-	 * information and the number of channels
-	 */
-	id = hpet_readl(HPET_ID);
-
-#ifdef CONFIG_HPET_EMULATE_RTC
-	/*
-	 * The legacy routing mode needs at least two channels, tick timer
-	 * and the rtc emulation channel.
-	 */
-	if (!(id & HPET_ID_NUMBER))
-		goto out_nohpet;
-#endif
-
 	/* Start the counter */
 	hpet_start_counter();
 
@@ -298,7 +343,7 @@
 	if (t1 == read_hpet()) {
 		printk(KERN_WARNING
 		       "HPET counter not counting. HPET disabled\n");
-		goto out_nohpet;
+		return -ENODEV;
 	}
 
 	/* Initialize and register HPET clocksource
@@ -319,27 +364,84 @@
 
 	clocksource_register(&clocksource_hpet);
 
+	return 0;
+}
+
+/*
+ * Try to setup the HPET timer
+ */
+int __init hpet_enable(void)
+{
+	unsigned long id;
+
+	if (!is_hpet_capable())
+		return 0;
+
+	hpet_set_mapping();
+
+	/*
+	 * Read the period and check for a sane value:
+	 */
+	hpet_period = hpet_readl(HPET_PERIOD);
+	if (hpet_period < HPET_MIN_PERIOD || hpet_period > HPET_MAX_PERIOD)
+		goto out_nohpet;
+
+	/*
+	 * Read the HPET ID register to retrieve the IRQ routing
+	 * information and the number of channels
+	 */
+	id = hpet_readl(HPET_ID);
+
+#ifdef CONFIG_HPET_EMULATE_RTC
+	/*
+	 * The legacy routing mode needs at least two channels, tick timer
+	 * and the rtc emulation channel.
+	 */
+	if (!(id & HPET_ID_NUMBER))
+		goto out_nohpet;
+#endif
+
+	if (hpet_clocksource_register())
+		goto out_nohpet;
+
 	if (id & HPET_ID_LEGSUP) {
-		hpet_enable_int();
-		hpet_reserve_platform_timers(id);
-		/*
-		 * Start hpet with the boot cpu mask and make it
-		 * global after the IO_APIC has been initialized.
-		 */
-		hpet_clockevent.cpumask = cpumask_of_cpu(smp_processor_id());
-		clockevents_register_device(&hpet_clockevent);
-		global_clock_event = &hpet_clockevent;
+		hpet_legacy_clockevent_register();
 		return 1;
 	}
 	return 0;
 
 out_nohpet:
-	iounmap(hpet_virt_address);
-	hpet_virt_address = NULL;
+	hpet_clear_mapping();
 	boot_hpet_disable = 1;
 	return 0;
 }
 
+/*
+ * Needs to be late, as the reserve_timer code calls kalloc !
+ *
+ * Not a problem on i386 as hpet_enable is called from late_time_init,
+ * but on x86_64 it is necessary !
+ */
+static __init int hpet_late_init(void)
+{
+	if (boot_hpet_disable)
+		return -ENODEV;
+
+	if (!hpet_address) {
+		if (!force_hpet_address)
+			return -ENODEV;
+
+		hpet_address = force_hpet_address;
+		hpet_enable();
+		if (!hpet_virt_address)
+			return -ENODEV;
+	}
+
+	hpet_reserve_platform_timers(hpet_readl(HPET_ID));
+
+	return 0;
+}
+fs_initcall(hpet_late_init);
 
 #ifdef CONFIG_HPET_EMULATE_RTC
 
diff --git a/arch/x86/kernel/hpet_64.c b/arch/x86/kernel/hpet_64.c
deleted file mode 100644
index e2d1b91..0000000
--- a/arch/x86/kernel/hpet_64.c
+++ /dev/null
@@ -1,493 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/mc146818rtc.h>
-#include <linux/time.h>
-#include <linux/clocksource.h>
-#include <linux/ioport.h>
-#include <linux/acpi.h>
-#include <linux/hpet.h>
-#include <asm/pgtable.h>
-#include <asm/vsyscall.h>
-#include <asm/timex.h>
-#include <asm/hpet.h>
-
-#define HPET_MASK	0xFFFFFFFF
-#define HPET_SHIFT	22
-
-/* FSEC = 10^-15 NSEC = 10^-9 */
-#define FSEC_PER_NSEC	1000000
-
-int nohpet __initdata;
-
-unsigned long hpet_address;
-unsigned long hpet_period;	/* fsecs / HPET clock */
-unsigned long hpet_tick;	/* HPET clocks / interrupt */
-
-int hpet_use_timer;		/* Use counter of hpet for time keeping,
-				 * otherwise PIT
-				 */
-
-#ifdef	CONFIG_HPET
-static __init int late_hpet_init(void)
-{
-	struct hpet_data	hd;
-	unsigned int 		ntimer;
-
-	if (!hpet_address)
-        	return 0;
-
-	memset(&hd, 0, sizeof(hd));
-
-	ntimer = hpet_readl(HPET_ID);
-	ntimer = (ntimer & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT;
-	ntimer++;
-
-	/*
-	 * Register with driver.
-	 * Timer0 and Timer1 is used by platform.
-	 */
-	hd.hd_phys_address = hpet_address;
-	hd.hd_address = (void __iomem *)fix_to_virt(FIX_HPET_BASE);
-	hd.hd_nirqs = ntimer;
-	hd.hd_flags = HPET_DATA_PLATFORM;
-	hpet_reserve_timer(&hd, 0);
-#ifdef	CONFIG_HPET_EMULATE_RTC
-	hpet_reserve_timer(&hd, 1);
-#endif
-	hd.hd_irq[0] = HPET_LEGACY_8254;
-	hd.hd_irq[1] = HPET_LEGACY_RTC;
-	if (ntimer > 2) {
-		struct hpet		*hpet;
-		struct hpet_timer	*timer;
-		int			i;
-
-		hpet = (struct hpet *) fix_to_virt(FIX_HPET_BASE);
-		timer = &hpet->hpet_timers[2];
-		for (i = 2; i < ntimer; timer++, i++)
-			hd.hd_irq[i] = (timer->hpet_config &
-					Tn_INT_ROUTE_CNF_MASK) >>
-				Tn_INT_ROUTE_CNF_SHIFT;
-
-	}
-
-	hpet_alloc(&hd);
-	return 0;
-}
-fs_initcall(late_hpet_init);
-#endif
-
-int hpet_timer_stop_set_go(unsigned long tick)
-{
-	unsigned int cfg;
-
-/*
- * Stop the timers and reset the main counter.
- */
-
-	cfg = hpet_readl(HPET_CFG);
-	cfg &= ~(HPET_CFG_ENABLE | HPET_CFG_LEGACY);
-	hpet_writel(cfg, HPET_CFG);
-	hpet_writel(0, HPET_COUNTER);
-	hpet_writel(0, HPET_COUNTER + 4);
-
-/*
- * Set up timer 0, as periodic with first interrupt to happen at hpet_tick,
- * and period also hpet_tick.
- */
-	if (hpet_use_timer) {
-		hpet_writel(HPET_TN_ENABLE | HPET_TN_PERIODIC | HPET_TN_SETVAL |
-		    HPET_TN_32BIT, HPET_T0_CFG);
-		hpet_writel(hpet_tick, HPET_T0_CMP); /* next interrupt */
-		hpet_writel(hpet_tick, HPET_T0_CMP); /* period */
-		cfg |= HPET_CFG_LEGACY;
-	}
-/*
- * Go!
- */
-
-	cfg |= HPET_CFG_ENABLE;
-	hpet_writel(cfg, HPET_CFG);
-
-	return 0;
-}
-
-static cycle_t read_hpet(void)
-{
-	return (cycle_t)hpet_readl(HPET_COUNTER);
-}
-
-static cycle_t __vsyscall_fn vread_hpet(void)
-{
-	return readl((void __iomem *)fix_to_virt(VSYSCALL_HPET) + 0xf0);
-}
-
-struct clocksource clocksource_hpet = {
-	.name		= "hpet",
-	.rating		= 250,
-	.read		= read_hpet,
-	.mask		= (cycle_t)HPET_MASK,
-	.mult		= 0, /* set below */
-	.shift		= HPET_SHIFT,
-	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
-	.vread		= vread_hpet,
-};
-
-int __init hpet_arch_init(void)
-{
-	unsigned int id;
-	u64 tmp;
-
-	if (!hpet_address)
-		return -1;
-	set_fixmap_nocache(FIX_HPET_BASE, hpet_address);
-	__set_fixmap(VSYSCALL_HPET, hpet_address, PAGE_KERNEL_VSYSCALL_NOCACHE);
-
-/*
- * Read the period, compute tick and quotient.
- */
-
-	id = hpet_readl(HPET_ID);
-
-	if (!(id & HPET_ID_VENDOR) || !(id & HPET_ID_NUMBER))
-		return -1;
-
-	hpet_period = hpet_readl(HPET_PERIOD);
-	if (hpet_period < 100000 || hpet_period > 100000000)
-		return -1;
-
-	hpet_tick = (FSEC_PER_TICK + hpet_period / 2) / hpet_period;
-
-	hpet_use_timer = (id & HPET_ID_LEGSUP);
-
-	/*
-	 * hpet period is in femto seconds per cycle
-	 * so we need to convert this to ns/cyc units
-	 * aproximated by mult/2^shift
-	 *
-	 *  fsec/cyc * 1nsec/1000000fsec = nsec/cyc = mult/2^shift
-	 *  fsec/cyc * 1ns/1000000fsec * 2^shift = mult
-	 *  fsec/cyc * 2^shift * 1nsec/1000000fsec = mult
-	 *  (fsec/cyc << shift)/1000000 = mult
-	 *  (hpet_period << shift)/FSEC_PER_NSEC = mult
-	 */
-	tmp = (u64)hpet_period << HPET_SHIFT;
-	do_div(tmp, FSEC_PER_NSEC);
-	clocksource_hpet.mult = (u32)tmp;
-	clocksource_register(&clocksource_hpet);
-
-	return hpet_timer_stop_set_go(hpet_tick);
-}
-
-int hpet_reenable(void)
-{
-	return hpet_timer_stop_set_go(hpet_tick);
-}
-
-/*
- * calibrate_tsc() calibrates the processor TSC in a very simple way, comparing
- * it to the HPET timer of known frequency.
- */
-
-#define TICK_COUNT 100000000
-#define SMI_THRESHOLD 50000
-#define MAX_TRIES  5
-
-/*
- * Some platforms take periodic SMI interrupts with 5ms duration. Make sure none
- * occurs between the reads of the hpet & TSC.
- */
-static void __init read_hpet_tsc(int *hpet, int *tsc)
-{
-	int tsc1, tsc2, hpet1, i;
-
-	for (i = 0; i < MAX_TRIES; i++) {
-		tsc1 = get_cycles_sync();
-		hpet1 = hpet_readl(HPET_COUNTER);
-		tsc2 = get_cycles_sync();
-		if ((tsc2 - tsc1) < SMI_THRESHOLD)
-			break;
-	}
-	*hpet = hpet1;
-	*tsc = tsc2;
-}
-
-unsigned int __init hpet_calibrate_tsc(void)
-{
-	int tsc_start, hpet_start;
-	int tsc_now, hpet_now;
-	unsigned long flags;
-
-	local_irq_save(flags);
-
-	read_hpet_tsc(&hpet_start, &tsc_start);
-
-	do {
-		local_irq_disable();
-		read_hpet_tsc(&hpet_now, &tsc_now);
-		local_irq_restore(flags);
-	} while ((tsc_now - tsc_start) < TICK_COUNT &&
-		(hpet_now - hpet_start) < TICK_COUNT);
-
-	return (tsc_now - tsc_start) * 1000000000L
-		/ ((hpet_now - hpet_start) * hpet_period / 1000);
-}
-
-#ifdef CONFIG_HPET_EMULATE_RTC
-/* HPET in LegacyReplacement Mode eats up RTC interrupt line. When, HPET
- * is enabled, we support RTC interrupt functionality in software.
- * RTC has 3 kinds of interrupts:
- * 1) Update Interrupt - generate an interrupt, every sec, when RTC clock
- *    is updated
- * 2) Alarm Interrupt - generate an interrupt at a specific time of day
- * 3) Periodic Interrupt - generate periodic interrupt, with frequencies
- *    2Hz-8192Hz (2Hz-64Hz for non-root user) (all freqs in powers of 2)
- * (1) and (2) above are implemented using polling at a frequency of
- * 64 Hz. The exact frequency is a tradeoff between accuracy and interrupt
- * overhead. (DEFAULT_RTC_INT_FREQ)
- * For (3), we use interrupts at 64Hz or user specified periodic
- * frequency, whichever is higher.
- */
-#include <linux/rtc.h>
-
-#define DEFAULT_RTC_INT_FREQ 	64
-#define RTC_NUM_INTS 		1
-
-static unsigned long UIE_on;
-static unsigned long prev_update_sec;
-
-static unsigned long AIE_on;
-static struct rtc_time alarm_time;
-
-static unsigned long PIE_on;
-static unsigned long PIE_freq = DEFAULT_RTC_INT_FREQ;
-static unsigned long PIE_count;
-
-static unsigned long hpet_rtc_int_freq; /* RTC interrupt frequency */
-static unsigned int hpet_t1_cmp; /* cached comparator register */
-
-int is_hpet_enabled(void)
-{
-	return hpet_address != 0;
-}
-
-/*
- * Timer 1 for RTC, we do not use periodic interrupt feature,
- * even if HPET supports periodic interrupts on Timer 1.
- * The reason being, to set up a periodic interrupt in HPET, we need to
- * stop the main counter. And if we do that everytime someone diables/enables
- * RTC, we will have adverse effect on main kernel timer running on Timer 0.
- * So, for the time being, simulate the periodic interrupt in software.
- *
- * hpet_rtc_timer_init() is called for the first time and during subsequent
- * interuppts reinit happens through hpet_rtc_timer_reinit().
- */
-int hpet_rtc_timer_init(void)
-{
-	unsigned int cfg, cnt;
-	unsigned long flags;
-
-	if (!is_hpet_enabled())
-		return 0;
-	/*
-	 * Set the counter 1 and enable the interrupts.
-	 */
-	if (PIE_on && (PIE_freq > DEFAULT_RTC_INT_FREQ))
-		hpet_rtc_int_freq = PIE_freq;
-	else
-		hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ;
-
-	local_irq_save(flags);
-
-	cnt = hpet_readl(HPET_COUNTER);
-	cnt += ((hpet_tick*HZ)/hpet_rtc_int_freq);
-	hpet_writel(cnt, HPET_T1_CMP);
-	hpet_t1_cmp = cnt;
-
-	cfg = hpet_readl(HPET_T1_CFG);
-	cfg &= ~HPET_TN_PERIODIC;
-	cfg |= HPET_TN_ENABLE | HPET_TN_32BIT;
-	hpet_writel(cfg, HPET_T1_CFG);
-
-	local_irq_restore(flags);
-
-	return 1;
-}
-
-static void hpet_rtc_timer_reinit(void)
-{
-	unsigned int cfg, cnt, ticks_per_int, lost_ints;
-
-	if (unlikely(!(PIE_on | AIE_on | UIE_on))) {
-		cfg = hpet_readl(HPET_T1_CFG);
-		cfg &= ~HPET_TN_ENABLE;
-		hpet_writel(cfg, HPET_T1_CFG);
-		return;
-	}
-
-	if (PIE_on && (PIE_freq > DEFAULT_RTC_INT_FREQ))
-		hpet_rtc_int_freq = PIE_freq;
-	else
-		hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ;
-
-	/* It is more accurate to use the comparator value than current count.*/
-	ticks_per_int = hpet_tick * HZ / hpet_rtc_int_freq;
-	hpet_t1_cmp += ticks_per_int;
-	hpet_writel(hpet_t1_cmp, HPET_T1_CMP);
-
-	/*
-	 * If the interrupt handler was delayed too long, the write above tries
-	 * to schedule the next interrupt in the past and the hardware would
-	 * not interrupt until the counter had wrapped around.
-	 * So we have to check that the comparator wasn't set to a past time.
-	 */
-	cnt = hpet_readl(HPET_COUNTER);
-	if (unlikely((int)(cnt - hpet_t1_cmp) > 0)) {
-		lost_ints = (cnt - hpet_t1_cmp) / ticks_per_int + 1;
-		/* Make sure that, even with the time needed to execute
-		 * this code, the next scheduled interrupt has been moved
-		 * back to the future: */
-		lost_ints++;
-
-		hpet_t1_cmp += lost_ints * ticks_per_int;
-		hpet_writel(hpet_t1_cmp, HPET_T1_CMP);
-
-		if (PIE_on)
-			PIE_count += lost_ints;
-
-		if (printk_ratelimit())
-			printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n",
-			       hpet_rtc_int_freq);
-	}
-}
-
-/*
- * The functions below are called from rtc driver.
- * Return 0 if HPET is not being used.
- * Otherwise do the necessary changes and return 1.
- */
-int hpet_mask_rtc_irq_bit(unsigned long bit_mask)
-{
-	if (!is_hpet_enabled())
-		return 0;
-
-	if (bit_mask & RTC_UIE)
-		UIE_on = 0;
-	if (bit_mask & RTC_PIE)
-		PIE_on = 0;
-	if (bit_mask & RTC_AIE)
-		AIE_on = 0;
-
-	return 1;
-}
-
-int hpet_set_rtc_irq_bit(unsigned long bit_mask)
-{
-	int timer_init_reqd = 0;
-
-	if (!is_hpet_enabled())
-		return 0;
-
-	if (!(PIE_on | AIE_on | UIE_on))
-		timer_init_reqd = 1;
-
-	if (bit_mask & RTC_UIE) {
-		UIE_on = 1;
-	}
-	if (bit_mask & RTC_PIE) {
-		PIE_on = 1;
-		PIE_count = 0;
-	}
-	if (bit_mask & RTC_AIE) {
-		AIE_on = 1;
-	}
-
-	if (timer_init_reqd)
-		hpet_rtc_timer_init();
-
-	return 1;
-}
-
-int hpet_set_alarm_time(unsigned char hrs, unsigned char min, unsigned char sec)
-{
-	if (!is_hpet_enabled())
-		return 0;
-
-	alarm_time.tm_hour = hrs;
-	alarm_time.tm_min = min;
-	alarm_time.tm_sec = sec;
-
-	return 1;
-}
-
-int hpet_set_periodic_freq(unsigned long freq)
-{
-	if (!is_hpet_enabled())
-		return 0;
-
-	PIE_freq = freq;
-	PIE_count = 0;
-
-	return 1;
-}
-
-int hpet_rtc_dropped_irq(void)
-{
-	if (!is_hpet_enabled())
-		return 0;
-
-	return 1;
-}
-
-irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
-{
-	struct rtc_time curr_time;
-	unsigned long rtc_int_flag = 0;
-	int call_rtc_interrupt = 0;
-
-	hpet_rtc_timer_reinit();
-
-	if (UIE_on | AIE_on) {
-		rtc_get_rtc_time(&curr_time);
-	}
-	if (UIE_on) {
-		if (curr_time.tm_sec != prev_update_sec) {
-			/* Set update int info, call real rtc int routine */
-			call_rtc_interrupt = 1;
-			rtc_int_flag = RTC_UF;
-			prev_update_sec = curr_time.tm_sec;
-		}
-	}
-	if (PIE_on) {
-		PIE_count++;
-		if (PIE_count >= hpet_rtc_int_freq/PIE_freq) {
-			/* Set periodic int info, call real rtc int routine */
-			call_rtc_interrupt = 1;
-			rtc_int_flag |= RTC_PF;
-			PIE_count = 0;
-		}
-	}
-	if (AIE_on) {
-		if ((curr_time.tm_sec == alarm_time.tm_sec) &&
-		    (curr_time.tm_min == alarm_time.tm_min) &&
-		    (curr_time.tm_hour == alarm_time.tm_hour)) {
-			/* Set alarm int info, call real rtc int routine */
-			call_rtc_interrupt = 1;
-			rtc_int_flag |= RTC_AF;
-		}
-	}
-	if (call_rtc_interrupt) {
-		rtc_int_flag |= (RTC_IRQF | (RTC_NUM_INTS << 8));
-		rtc_interrupt(rtc_int_flag, dev_id);
-	}
-	return IRQ_HANDLED;
-}
-#endif
-
-static int __init nohpet_setup(char *s)
-{
-	nohpet = 1;
-	return 1;
-}
-
-__setup("nohpet", nohpet_setup);
diff --git a/arch/x86/kernel/i8253_32.c b/arch/x86/kernel/i8253.c
similarity index 99%
rename from arch/x86/kernel/i8253_32.c
rename to arch/x86/kernel/i8253.c
index 6d839f2..ac15e4c 100644
--- a/arch/x86/kernel/i8253_32.c
+++ b/arch/x86/kernel/i8253.c
@@ -13,7 +13,6 @@
 #include <asm/delay.h>
 #include <asm/i8253.h>
 #include <asm/io.h>
-#include <asm/timer.h>
 
 DEFINE_SPINLOCK(i8253_lock);
 EXPORT_SYMBOL(i8253_lock);
@@ -120,6 +119,7 @@
 	global_clock_event = &pit_clockevent;
 }
 
+#ifndef CONFIG_X86_64
 /*
  * Since the PIT overflows every tick, its not very useful
  * to just read by itself. So use jiffies to emulate a free
@@ -204,3 +204,5 @@
 	return clocksource_register(&clocksource_pit);
 }
 arch_initcall(init_pit_clocksource);
+
+#endif
diff --git a/arch/x86/kernel/i8259_32.c b/arch/x86/kernel/i8259_32.c
index 0499cbe..679bb33 100644
--- a/arch/x86/kernel/i8259_32.c
+++ b/arch/x86/kernel/i8259_32.c
@@ -10,7 +10,6 @@
 #include <linux/sysdev.h>
 #include <linux/bitops.h>
 
-#include <asm/8253pit.h>
 #include <asm/atomic.h>
 #include <asm/system.h>
 #include <asm/io.h>
diff --git a/arch/x86/kernel/i8259_64.c b/arch/x86/kernel/i8259_64.c
index 948cae6..eb72976 100644
--- a/arch/x86/kernel/i8259_64.c
+++ b/arch/x86/kernel/i8259_64.c
@@ -444,46 +444,6 @@
 	}
 }
 
-static void setup_timer_hardware(void)
-{
-	outb_p(0x34,0x43);		/* binary, mode 2, LSB/MSB, ch 0 */
-	udelay(10);
-	outb_p(LATCH & 0xff , 0x40);	/* LSB */
-	udelay(10);
-	outb(LATCH >> 8 , 0x40);	/* MSB */
-}
-
-static int timer_resume(struct sys_device *dev)
-{
-	setup_timer_hardware();
-	return 0;
-}
-
-void i8254_timer_resume(void)
-{
-	setup_timer_hardware();
-}
-
-static struct sysdev_class timer_sysclass = {
-	set_kset_name("timer_pit"),
-	.resume		= timer_resume,
-};
-
-static struct sys_device device_timer = {
-	.id		= 0,
-	.cls		= &timer_sysclass,
-};
-
-static int __init init_timer_sysfs(void)
-{
-	int error = sysdev_class_register(&timer_sysclass);
-	if (!error)
-		error = sysdev_register(&device_timer);
-	return error;
-}
-
-device_initcall(init_timer_sysfs);
-
 void __init init_IRQ(void)
 {
 	int i;
@@ -533,12 +493,6 @@
 	set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
 	set_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
 
-	/*
-	 * Set the clock to HZ Hz, we already have a valid
-	 * vector now:
-	 */
-	setup_timer_hardware();
-
 	if (!acpi_ioapic)
 		setup_irq(2, &irq2);
 }
diff --git a/arch/x86/kernel/mfgpt_32.c b/arch/x86/kernel/mfgpt_32.c
new file mode 100644
index 0000000..0ab680f
--- /dev/null
+++ b/arch/x86/kernel/mfgpt_32.c
@@ -0,0 +1,362 @@
+/*
+ * Driver/API for AMD Geode Multi-Function General Purpose Timers (MFGPT)
+ *
+ * Copyright (C) 2006, Advanced Micro Devices, Inc.
+ * Copyright (C) 2007, Andres Salomon <dilinger@debian.org>
+ *
+ * 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.
+ *
+ * The MFGPTs are documented in AMD Geode CS5536 Companion Device Data Book.
+ */
+
+/*
+ * We are using the 32Khz input clock - its the only one that has the
+ * ranges we find desirable.  The following table lists the suitable
+ * divisors and the associated hz, minimum interval
+ * and the maximum interval:
+ *
+ *  Divisor   Hz      Min Delta (S) Max Delta (S)
+ *   1        32000     .0005          2.048
+ *   2        16000      .001          4.096
+ *   4         8000      .002          8.192
+ *   8         4000      .004         16.384
+ *   16        2000      .008         32.768
+ *   32        1000      .016         65.536
+ *   64         500      .032        131.072
+ *  128         250      .064        262.144
+ *  256         125      .128        524.288
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <asm/geode.h>
+
+#define F_AVAIL    0x01
+
+static struct mfgpt_timer_t {
+	int flags;
+	struct module *owner;
+} mfgpt_timers[MFGPT_MAX_TIMERS];
+
+/* Selected from the table above */
+
+#define MFGPT_DIVISOR 16
+#define MFGPT_SCALE  4     /* divisor = 2^(scale) */
+#define MFGPT_HZ  (32000 / MFGPT_DIVISOR)
+#define MFGPT_PERIODIC (MFGPT_HZ / HZ)
+
+#ifdef CONFIG_GEODE_MFGPT_TIMER
+static int __init mfgpt_timer_setup(void);
+#else
+#define mfgpt_timer_setup() (0)
+#endif
+
+/* Allow for disabling of MFGPTs */
+static int disable;
+static int __init mfgpt_disable(char *s)
+{
+	disable = 1;
+	return 1;
+}
+__setup("nomfgpt", mfgpt_disable);
+
+/*
+ * Check whether any MFGPTs are available for the kernel to use.  In most
+ * cases, firmware that uses AMD's VSA code will claim all timers during
+ * bootup; we certainly don't want to take them if they're already in use.
+ * In other cases (such as with VSAless OpenFirmware), the system firmware
+ * leaves timers available for us to use.
+ */
+int __init geode_mfgpt_detect(void)
+{
+	int count = 0, i;
+	u16 val;
+
+	if (disable) {
+		printk(KERN_INFO "geode-mfgpt:  Skipping MFGPT setup\n");
+		return 0;
+	}
+
+	for (i = 0; i < MFGPT_MAX_TIMERS; i++) {
+		val = geode_mfgpt_read(i, MFGPT_REG_SETUP);
+		if (!(val & MFGPT_SETUP_SETUP)) {
+			mfgpt_timers[i].flags = F_AVAIL;
+			count++;
+		}
+	}
+
+	/* set up clock event device, if desired */
+	i = mfgpt_timer_setup();
+
+	return count;
+}
+
+int geode_mfgpt_toggle_event(int timer, int cmp, int event, int enable)
+{
+	u32 msr, mask, value, dummy;
+	int shift = (cmp == MFGPT_CMP1) ? 0 : 8;
+
+	if (timer < 0 || timer >= MFGPT_MAX_TIMERS)
+		return -EIO;
+
+	/*
+	 * The register maps for these are described in sections 6.17.1.x of
+	 * the AMD Geode CS5536 Companion Device Data Book.
+	 */
+	switch (event) {
+	case MFGPT_EVENT_RESET:
+		/*
+		 * XXX: According to the docs, we cannot reset timers above
+		 * 6; that is, resets for 7 and 8 will be ignored.  Is this
+		 * a problem?   -dilinger
+		 */
+		msr = MFGPT_NR_MSR;
+		mask = 1 << (timer + 24);
+		break;
+
+	case MFGPT_EVENT_NMI:
+		msr = MFGPT_NR_MSR;
+		mask = 1 << (timer + shift);
+		break;
+
+	case MFGPT_EVENT_IRQ:
+		msr = MFGPT_IRQ_MSR;
+		mask = 1 << (timer + shift);
+		break;
+
+	default:
+		return -EIO;
+	}
+
+	rdmsr(msr, value, dummy);
+
+	if (enable)
+		value |= mask;
+	else
+		value &= ~mask;
+
+	wrmsr(msr, value, dummy);
+	return 0;
+}
+
+int geode_mfgpt_set_irq(int timer, int cmp, int irq, int enable)
+{
+	u32 val, dummy;
+	int offset;
+
+	if (timer < 0 || timer >= MFGPT_MAX_TIMERS)
+		return -EIO;
+
+	if (geode_mfgpt_toggle_event(timer, cmp, MFGPT_EVENT_IRQ, enable))
+		return -EIO;
+
+	rdmsr(MSR_PIC_ZSEL_LOW, val, dummy);
+
+	offset = (timer % 4) * 4;
+
+	val &= ~((0xF << offset) | (0xF << (offset + 16)));
+
+	if (enable) {
+		val |= (irq & 0x0F) << (offset);
+		val |= (irq & 0x0F) << (offset + 16);
+	}
+
+	wrmsr(MSR_PIC_ZSEL_LOW, val, dummy);
+	return 0;
+}
+
+static int mfgpt_get(int timer, struct module *owner)
+{
+	mfgpt_timers[timer].flags &= ~F_AVAIL;
+	mfgpt_timers[timer].owner = owner;
+	printk(KERN_INFO "geode-mfgpt:  Registered timer %d\n", timer);
+	return timer;
+}
+
+int geode_mfgpt_alloc_timer(int timer, int domain, struct module *owner)
+{
+	int i;
+
+	if (!geode_get_dev_base(GEODE_DEV_MFGPT))
+		return -ENODEV;
+	if (timer >= MFGPT_MAX_TIMERS)
+		return -EIO;
+
+	if (timer < 0) {
+		/* Try to find an available timer */
+		for (i = 0; i < MFGPT_MAX_TIMERS; i++) {
+			if (mfgpt_timers[i].flags & F_AVAIL)
+				return mfgpt_get(i, owner);
+
+			if (i == 5 && domain == MFGPT_DOMAIN_WORKING)
+				break;
+		}
+	} else {
+		/* If they requested a specific timer, try to honor that */
+		if (mfgpt_timers[timer].flags & F_AVAIL)
+			return mfgpt_get(timer, owner);
+	}
+
+	/* No timers available - too bad */
+	return -1;
+}
+
+
+#ifdef CONFIG_GEODE_MFGPT_TIMER
+
+/*
+ * The MFPGT timers on the CS5536 provide us with suitable timers to use
+ * as clock event sources - not as good as a HPET or APIC, but certainly
+ * better then the PIT.  This isn't a general purpose MFGPT driver, but
+ * a simplified one designed specifically to act as a clock event source.
+ * For full details about the MFGPT, please consult the CS5536 data sheet.
+ */
+
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+
+static unsigned int mfgpt_tick_mode = CLOCK_EVT_MODE_SHUTDOWN;
+static u16 mfgpt_event_clock;
+
+static int irq = 7;
+static int __init mfgpt_setup(char *str)
+{
+	get_option(&str, &irq);
+	return 1;
+}
+__setup("mfgpt_irq=", mfgpt_setup);
+
+static inline void mfgpt_disable_timer(u16 clock)
+{
+	u16 val = geode_mfgpt_read(clock, MFGPT_REG_SETUP);
+	geode_mfgpt_write(clock, MFGPT_REG_SETUP, val & ~MFGPT_SETUP_CNTEN);
+}
+
+static int mfgpt_next_event(unsigned long, struct clock_event_device *);
+static void mfgpt_set_mode(enum clock_event_mode, struct clock_event_device *);
+
+static struct clock_event_device mfgpt_clockevent = {
+	.name = "mfgpt-timer",
+	.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+	.set_mode = mfgpt_set_mode,
+	.set_next_event = mfgpt_next_event,
+	.rating = 250,
+	.cpumask = CPU_MASK_ALL,
+	.shift = 32
+};
+
+static inline void mfgpt_start_timer(u16 clock, u16 delta)
+{
+	geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_CMP2, (u16) delta);
+	geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_COUNTER, 0);
+
+	geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP,
+			  MFGPT_SETUP_CNTEN | MFGPT_SETUP_CMP2);
+}
+
+static void mfgpt_set_mode(enum clock_event_mode mode,
+			   struct clock_event_device *evt)
+{
+	mfgpt_disable_timer(mfgpt_event_clock);
+
+	if (mode == CLOCK_EVT_MODE_PERIODIC)
+		mfgpt_start_timer(mfgpt_event_clock, MFGPT_PERIODIC);
+
+	mfgpt_tick_mode = mode;
+}
+
+static int mfgpt_next_event(unsigned long delta, struct clock_event_device *evt)
+{
+	mfgpt_start_timer(mfgpt_event_clock, delta);
+	return 0;
+}
+
+/* Assume (foolishly?), that this interrupt was due to our tick */
+
+static irqreturn_t mfgpt_tick(int irq, void *dev_id)
+{
+	if (mfgpt_tick_mode == CLOCK_EVT_MODE_SHUTDOWN)
+		return IRQ_HANDLED;
+
+	/* Turn off the clock */
+	mfgpt_disable_timer(mfgpt_event_clock);
+
+	/* Clear the counter */
+	geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_COUNTER, 0);
+
+	/* Restart the clock in periodic mode */
+
+	if (mfgpt_tick_mode == CLOCK_EVT_MODE_PERIODIC) {
+		geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP,
+				  MFGPT_SETUP_CNTEN | MFGPT_SETUP_CMP2);
+	}
+
+	mfgpt_clockevent.event_handler(&mfgpt_clockevent);
+	return IRQ_HANDLED;
+}
+
+static struct irqaction mfgptirq  = {
+	.handler = mfgpt_tick,
+	.flags = IRQF_DISABLED | IRQF_NOBALANCING,
+	.mask = CPU_MASK_NONE,
+	.name = "mfgpt-timer"
+};
+
+static int __init mfgpt_timer_setup(void)
+{
+	int timer, ret;
+	u16 val;
+
+	timer = geode_mfgpt_alloc_timer(MFGPT_TIMER_ANY, MFGPT_DOMAIN_WORKING,
+			THIS_MODULE);
+	if (timer < 0) {
+		printk(KERN_ERR
+		       "mfgpt-timer:  Could not allocate a MFPGT timer\n");
+		return -ENODEV;
+	}
+
+	mfgpt_event_clock = timer;
+	/* Set the clock scale and enable the event mode for CMP2 */
+	val = MFGPT_SCALE | (3 << 8);
+
+	geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP, val);
+
+	/* Set up the IRQ on the MFGPT side */
+	if (geode_mfgpt_setup_irq(mfgpt_event_clock, MFGPT_CMP2, irq)) {
+		printk(KERN_ERR "mfgpt-timer:  Could not set up IRQ %d\n", irq);
+		return -EIO;
+	}
+
+	/* And register it with the kernel */
+	ret = setup_irq(irq, &mfgptirq);
+
+	if (ret) {
+		printk(KERN_ERR
+		       "mfgpt-timer:  Unable to set up the interrupt.\n");
+		goto err;
+	}
+
+	/* Set up the clock event */
+	mfgpt_clockevent.mult = div_sc(MFGPT_HZ, NSEC_PER_SEC, 32);
+	mfgpt_clockevent.min_delta_ns = clockevent_delta2ns(0xF,
+			&mfgpt_clockevent);
+	mfgpt_clockevent.max_delta_ns = clockevent_delta2ns(0xFFFE,
+			&mfgpt_clockevent);
+
+	printk(KERN_INFO
+	       "mfgpt-timer:  registering the MFGT timer as a clock event.\n");
+	clockevents_register_device(&mfgpt_clockevent);
+
+	return 0;
+
+err:
+	geode_mfgpt_release_irq(mfgpt_event_clock, MFGPT_CMP2, irq);
+	printk(KERN_ERR
+	       "mfgpt-timer:  Unable to set up the MFGPT clock source\n");
+	return -EIO;
+}
+
+#endif
diff --git a/arch/x86/kernel/nmi_32.c b/arch/x86/kernel/nmi_32.c
index c7227e2..95d3fc2 100644
--- a/arch/x86/kernel/nmi_32.c
+++ b/arch/x86/kernel/nmi_32.c
@@ -353,7 +353,8 @@
 	 * Take the local apic timer and PIT/HPET into account. We don't
 	 * know which one is active, when we have highres/dyntick on
 	 */
-	sum = per_cpu(irq_stat, cpu).apic_timer_irqs + kstat_cpu(cpu).irqs[0];
+	sum = per_cpu(irq_stat, cpu).apic_timer_irqs +
+		per_cpu(irq_stat, cpu).irq0_irqs;
 
 	/* if the none of the timers isn't firing, this cpu isn't doing much */
 	if (!touched && last_irq_sums[cpu] == sum) {
diff --git a/arch/x86/kernel/nmi_64.c b/arch/x86/kernel/nmi_64.c
index 0ec6d2d..e60ac0d 100644
--- a/arch/x86/kernel/nmi_64.c
+++ b/arch/x86/kernel/nmi_64.c
@@ -329,7 +329,7 @@
 		touched = 1;
 	}
 
-	sum = read_pda(apic_timer_irqs);
+	sum = read_pda(apic_timer_irqs) + read_pda(irq0_irqs);
 	if (__get_cpu_var(nmi_touch)) {
 		__get_cpu_var(nmi_touch) = 0;
 		touched = 1;
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 9895655..6f9dbbe 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -38,6 +38,7 @@
 #include <linux/notifier.h>
 #include <linux/kprobes.h>
 #include <linux/kdebug.h>
+#include <linux/tick.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -208,6 +209,8 @@
 			if (__get_cpu_var(cpu_idle_state))
 				__get_cpu_var(cpu_idle_state) = 0;
 
+			tick_nohz_stop_sched_tick();
+
 			rmb();
 			idle = pm_idle;
 			if (!idle)
@@ -228,6 +231,7 @@
 			__exit_idle();
 		}
 
+		tick_nohz_restart_sched_tick();
 		preempt_enable_no_resched();
 		schedule();
 		preempt_disable();
diff --git a/arch/x86/kernel/quirks.c b/arch/x86/kernel/quirks.c
index 6722469..d769e20 100644
--- a/arch/x86/kernel/quirks.c
+++ b/arch/x86/kernel/quirks.c
@@ -4,6 +4,8 @@
 #include <linux/pci.h>
 #include <linux/irq.h>
 
+#include <asm/hpet.h>
+
 #if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_SMP) && defined(CONFIG_PCI)
 
 static void __devinit quirk_intel_irqbalance(struct pci_dev *dev)
@@ -47,3 +49,206 @@
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_E7525_MCH,	quirk_intel_irqbalance);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_E7520_MCH,	quirk_intel_irqbalance);
 #endif
+
+#if defined(CONFIG_HPET_TIMER)
+unsigned long force_hpet_address;
+
+static enum {
+	NONE_FORCE_HPET_RESUME,
+	OLD_ICH_FORCE_HPET_RESUME,
+	ICH_FORCE_HPET_RESUME
+} force_hpet_resume_type;
+
+static void __iomem *rcba_base;
+
+static void ich_force_hpet_resume(void)
+{
+	u32 val;
+
+	if (!force_hpet_address)
+		return;
+
+	if (rcba_base == NULL)
+		BUG();
+
+	/* read the Function Disable register, dword mode only */
+	val = readl(rcba_base + 0x3404);
+	if (!(val & 0x80)) {
+		/* HPET disabled in HPTC. Trying to enable */
+		writel(val | 0x80, rcba_base + 0x3404);
+	}
+
+	val = readl(rcba_base + 0x3404);
+	if (!(val & 0x80))
+		BUG();
+	else
+		printk(KERN_DEBUG "Force enabled HPET at resume\n");
+
+	return;
+}
+
+static void ich_force_enable_hpet(struct pci_dev *dev)
+{
+	u32 val;
+	u32 uninitialized_var(rcba);
+	int err = 0;
+
+	if (hpet_address || force_hpet_address)
+		return;
+
+	pci_read_config_dword(dev, 0xF0, &rcba);
+	rcba &= 0xFFFFC000;
+	if (rcba == 0) {
+		printk(KERN_DEBUG "RCBA disabled. Cannot force enable HPET\n");
+		return;
+	}
+
+	/* use bits 31:14, 16 kB aligned */
+	rcba_base = ioremap_nocache(rcba, 0x4000);
+	if (rcba_base == NULL) {
+		printk(KERN_DEBUG "ioremap failed. Cannot force enable HPET\n");
+		return;
+	}
+
+	/* read the Function Disable register, dword mode only */
+	val = readl(rcba_base + 0x3404);
+
+	if (val & 0x80) {
+		/* HPET is enabled in HPTC. Just not reported by BIOS */
+		val = val & 0x3;
+		force_hpet_address = 0xFED00000 | (val << 12);
+		printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n",
+			       force_hpet_address);
+		iounmap(rcba_base);
+		return;
+	}
+
+	/* HPET disabled in HPTC. Trying to enable */
+	writel(val | 0x80, rcba_base + 0x3404);
+
+	val = readl(rcba_base + 0x3404);
+	if (!(val & 0x80)) {
+		err = 1;
+	} else {
+		val = val & 0x3;
+		force_hpet_address = 0xFED00000 | (val << 12);
+	}
+
+	if (err) {
+		force_hpet_address = 0;
+		iounmap(rcba_base);
+		printk(KERN_DEBUG "Failed to force enable HPET\n");
+	} else {
+		force_hpet_resume_type = ICH_FORCE_HPET_RESUME;
+		printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n",
+			       force_hpet_address);
+	}
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_0,
+                         ich_force_enable_hpet);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1,
+                         ich_force_enable_hpet);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0,
+                         ich_force_enable_hpet);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1,
+                         ich_force_enable_hpet);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31,
+                         ich_force_enable_hpet);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_1,
+                         ich_force_enable_hpet);
+
+
+static struct pci_dev *cached_dev;
+
+static void old_ich_force_hpet_resume(void)
+{
+	u32 val;
+	u32 uninitialized_var(gen_cntl);
+
+	if (!force_hpet_address || !cached_dev)
+		return;
+
+	pci_read_config_dword(cached_dev, 0xD0, &gen_cntl);
+	gen_cntl &= (~(0x7 << 15));
+	gen_cntl |= (0x4 << 15);
+
+	pci_write_config_dword(cached_dev, 0xD0, gen_cntl);
+	pci_read_config_dword(cached_dev, 0xD0, &gen_cntl);
+	val = gen_cntl >> 15;
+	val &= 0x7;
+	if (val == 0x4)
+		printk(KERN_DEBUG "Force enabled HPET at resume\n");
+	else
+		BUG();
+}
+
+static void old_ich_force_enable_hpet(struct pci_dev *dev)
+{
+	u32 val;
+	u32 uninitialized_var(gen_cntl);
+
+	if (hpet_address || force_hpet_address)
+		return;
+
+	pci_read_config_dword(dev, 0xD0, &gen_cntl);
+	/*
+	 * Bit 17 is HPET enable bit.
+	 * Bit 16:15 control the HPET base address.
+	 */
+	val = gen_cntl >> 15;
+	val &= 0x7;
+	if (val & 0x4) {
+		val &= 0x3;
+		force_hpet_address = 0xFED00000 | (val << 12);
+		printk(KERN_DEBUG "HPET at base address 0x%lx\n",
+			       force_hpet_address);
+		return;
+	}
+
+	/*
+	 * HPET is disabled. Trying enabling at FED00000 and check
+	 * whether it sticks
+	 */
+	gen_cntl &= (~(0x7 << 15));
+	gen_cntl |= (0x4 << 15);
+	pci_write_config_dword(dev, 0xD0, gen_cntl);
+
+	pci_read_config_dword(dev, 0xD0, &gen_cntl);
+
+	val = gen_cntl >> 15;
+	val &= 0x7;
+	if (val & 0x4) {
+		/* HPET is enabled in HPTC. Just not reported by BIOS */
+		val &= 0x3;
+		force_hpet_address = 0xFED00000 | (val << 12);
+		printk(KERN_DEBUG "Force enabled HPET at base address 0x%lx\n",
+			       force_hpet_address);
+		cached_dev = dev;
+		force_hpet_resume_type = OLD_ICH_FORCE_HPET_RESUME;
+		return;
+	}
+
+	printk(KERN_DEBUG "Failed to force enable HPET\n");
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0,
+                         old_ich_force_enable_hpet);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_12,
+                         old_ich_force_enable_hpet);
+
+void force_hpet_resume(void)
+{
+	switch (force_hpet_resume_type) {
+	    case ICH_FORCE_HPET_RESUME:
+		return ich_force_hpet_resume();
+
+	    case OLD_ICH_FORCE_HPET_RESUME:
+		return old_ich_force_hpet_resume();
+
+	    default:
+		break;
+	}
+}
+
+#endif
diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c
index af838f6..32054bf 100644
--- a/arch/x86/kernel/setup_64.c
+++ b/arch/x86/kernel/setup_64.c
@@ -546,6 +546,37 @@
 #endif
 }
 
+#define ENABLE_C1E_MASK		0x18000000
+#define CPUID_PROCESSOR_SIGNATURE	1
+#define CPUID_XFAM		0x0ff00000
+#define CPUID_XFAM_K8		0x00000000
+#define CPUID_XFAM_10H		0x00100000
+#define CPUID_XFAM_11H		0x00200000
+#define CPUID_XMOD		0x000f0000
+#define CPUID_XMOD_REV_F	0x00040000
+
+/* AMD systems with C1E don't have a working lAPIC timer. Check for that. */
+static __cpuinit int amd_apic_timer_broken(void)
+{
+	u32 lo, hi;
+	u32 eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
+	switch (eax & CPUID_XFAM) {
+	case CPUID_XFAM_K8:
+		if ((eax & CPUID_XMOD) < CPUID_XMOD_REV_F)
+			break;
+	case CPUID_XFAM_10H:
+	case CPUID_XFAM_11H:
+		rdmsr(MSR_K8_ENABLE_C1E, lo, hi);
+		if (lo & ENABLE_C1E_MASK)
+			return 1;
+		break;
+	default:
+		/* err on the side of caution */
+		return 1;
+	}
+	return 0;
+}
+
 static void __cpuinit init_amd(struct cpuinfo_x86 *c)
 {
 	unsigned level;
@@ -617,6 +648,9 @@
 	/* Family 10 doesn't support C states in MWAIT so don't use it */
 	if (c->x86 == 0x10 && !force_mwait)
 		clear_bit(X86_FEATURE_MWAIT, &c->x86_capability);
+
+	if (amd_apic_timer_broken())
+		disable_apic_timer = 1;
 }
 
 static void __cpuinit detect_ht(struct cpuinfo_x86 *c)
diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c
index 32f5078..57ccf7c 100644
--- a/arch/x86/kernel/smpboot_64.c
+++ b/arch/x86/kernel/smpboot_64.c
@@ -223,8 +223,6 @@
 	local_irq_disable();
 	Dprintk("Stack at about %p\n",&cpuid);
 
-	disable_APIC_timer();
-
 	/*
 	 * Save our processor parameters
 	 */
@@ -348,8 +346,6 @@
 		enable_8259A_irq(0);
 	}
 
-	enable_APIC_timer();
-
 	/*
 	 * The sibling maps must be set before turing the online map on for
 	 * this cpu
diff --git a/arch/x86/kernel/time_32.c b/arch/x86/kernel/time_32.c
index 19a6c67..56dadfc 100644
--- a/arch/x86/kernel/time_32.c
+++ b/arch/x86/kernel/time_32.c
@@ -157,6 +157,9 @@
  */
 irqreturn_t timer_interrupt(int irq, void *dev_id)
 {
+	/* Keep nmi watchdog up to date */
+	per_cpu(irq_stat, smp_processor_id()).irq0_irqs++;
+
 #ifdef CONFIG_X86_IO_APIC
 	if (timer_ack) {
 		/*
diff --git a/arch/x86/kernel/time_64.c b/arch/x86/kernel/time_64.c
index 6d48a4e..e0134d6 100644
--- a/arch/x86/kernel/time_64.c
+++ b/arch/x86/kernel/time_64.c
@@ -28,11 +28,12 @@
 #include <linux/cpu.h>
 #include <linux/kallsyms.h>
 #include <linux/acpi.h>
+#include <linux/clockchips.h>
+
 #ifdef CONFIG_ACPI
 #include <acpi/achware.h>	/* for PM timer frequency */
 #include <acpi/acpi_bus.h>
 #endif
-#include <asm/8253pit.h>
 #include <asm/i8253.h>
 #include <asm/pgtable.h>
 #include <asm/vsyscall.h>
@@ -47,12 +48,8 @@
 #include <asm/nmi.h>
 #include <asm/vgtod.h>
 
-static char *timename = NULL;
-
 DEFINE_SPINLOCK(rtc_lock);
 EXPORT_SYMBOL(rtc_lock);
-DEFINE_SPINLOCK(i8253_lock);
-EXPORT_SYMBOL(i8253_lock);
 
 volatile unsigned long __jiffies __section_jiffies = INITIAL_JIFFIES;
 
@@ -153,45 +150,12 @@
 	return set_rtc_mmss(now.tv_sec);
 }
 
-void main_timer_handler(void)
+static irqreturn_t timer_event_interrupt(int irq, void *dev_id)
 {
-/*
- * Here we are in the timer irq handler. We have irqs locally disabled (so we
- * don't need spin_lock_irqsave()) but we don't know if the timer_bh is running
- * on the other CPU, so we need a lock. We also need to lock the vsyscall
- * variables, because both do_timer() and us change them -arca+vojtech
- */
+	add_pda(irq0_irqs, 1);
 
-	write_seqlock(&xtime_lock);
+	global_clock_event->event_handler(global_clock_event);
 
-/*
- * Do the timer stuff.
- */
-
-	do_timer(1);
-#ifndef CONFIG_SMP
-	update_process_times(user_mode(get_irq_regs()));
-#endif
-
-/*
- * In the SMP case we use the local APIC timer interrupt to do the profiling,
- * except when we simulate SMP mode on a uniprocessor system, in that case we
- * have to call the local interrupt handler.
- */
-
-	if (!using_apic_timer)
-		smp_local_timer_interrupt();
-
-	write_sequnlock(&xtime_lock);
-}
-
-static irqreturn_t timer_interrupt(int irq, void *dev_id)
-{
-	if (apic_runs_main_timer > 1)
-		return IRQ_HANDLED;
-	main_timer_handler();
-	if (using_apic_timer)
-		smp_send_timer_broadcast_ipi();
 	return IRQ_HANDLED;
 }
 
@@ -292,97 +256,21 @@
 	return pmc_now * tsc_khz / (tsc_now - tsc_start);
 }
 
-/*
- * pit_calibrate_tsc() uses the speaker output (channel 2) of
- * the PIT. This is better than using the timer interrupt output,
- * because we can read the value of the speaker with just one inb(),
- * where we need three i/o operations for the interrupt channel.
- * We count how many ticks the TSC does in 50 ms.
- */
-
-static unsigned int __init pit_calibrate_tsc(void)
-{
-	unsigned long start, end;
-	unsigned long flags;
-
-	spin_lock_irqsave(&i8253_lock, flags);
-
-	outb((inb(0x61) & ~0x02) | 0x01, 0x61);
-
-	outb(0xb0, 0x43);
-	outb((PIT_TICK_RATE / (1000 / 50)) & 0xff, 0x42);
-	outb((PIT_TICK_RATE / (1000 / 50)) >> 8, 0x42);
-	start = get_cycles_sync();
-	while ((inb(0x61) & 0x20) == 0);
-	end = get_cycles_sync();
-
-	spin_unlock_irqrestore(&i8253_lock, flags);
-
-	return (end - start) / 50;
-}
-
-#define PIT_MODE 0x43
-#define PIT_CH0  0x40
-
-static void __pit_init(int val, u8 mode)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&i8253_lock, flags);
-	outb_p(mode, PIT_MODE);
-	outb_p(val & 0xff, PIT_CH0);	/* LSB */
-	outb_p(val >> 8, PIT_CH0);	/* MSB */
-	spin_unlock_irqrestore(&i8253_lock, flags);
-}
-
-void __init pit_init(void)
-{
-	__pit_init(LATCH, 0x34); /* binary, mode 2, LSB/MSB, ch 0 */
-}
-
-void pit_stop_interrupt(void)
-{
-	__pit_init(0, 0x30); /* mode 0 */
-}
-
-void stop_timer_interrupt(void)
-{
-	char *name;
-	if (hpet_address) {
-		name = "HPET";
-		hpet_timer_stop_set_go(0);
-	} else {
-		name = "PIT";
-		pit_stop_interrupt();
-	}
-	printk(KERN_INFO "timer: %s interrupt stopped.\n", name);
-}
-
 static struct irqaction irq0 = {
-	.handler	= timer_interrupt,
-	.flags		= IRQF_DISABLED | IRQF_IRQPOLL,
+	.handler	= timer_event_interrupt,
+	.flags		= IRQF_DISABLED | IRQF_IRQPOLL | IRQF_NOBALANCING,
 	.mask		= CPU_MASK_NONE,
 	.name		= "timer"
 };
 
 void __init time_init(void)
 {
-	if (nohpet)
-		hpet_address = 0;
+	if (!hpet_enable())
+		setup_pit_timer();
 
-	if (hpet_arch_init())
-		hpet_address = 0;
+	setup_irq(0, &irq0);
 
-	if (hpet_use_timer) {
-		/* set tick_nsec to use the proper rate for HPET */
-		tick_nsec = TICK_NSEC_HPET;
-		tsc_khz = hpet_calibrate_tsc();
-		timename = "HPET";
-	} else {
-		pit_init();
-		tsc_khz = pit_calibrate_tsc();
-		timename = "PIT";
-	}
+	tsc_calibrate();
 
 	cpu_khz = tsc_khz;
 	if (cpu_has(&boot_cpu_data, X86_FEATURE_CONSTANT_TSC) &&
@@ -398,50 +286,7 @@
 	else
 		vgetcpu_mode = VGETCPU_LSL;
 
-	set_cyc2ns_scale(tsc_khz);
 	printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n",
 		cpu_khz / 1000, cpu_khz % 1000);
 	init_tsc_clocksource();
-
-	setup_irq(0, &irq0);
 }
-
-/*
- * sysfs support for the timer.
- */
-
-static int timer_suspend(struct sys_device *dev, pm_message_t state)
-{
-	return 0;
-}
-
-static int timer_resume(struct sys_device *dev)
-{
-	if (hpet_address)
-		hpet_reenable();
-	else
-		i8254_timer_resume();
-	return 0;
-}
-
-static struct sysdev_class timer_sysclass = {
-	.resume = timer_resume,
-	.suspend = timer_suspend,
-	set_kset_name("timer"),
-};
-
-/* XXX this sysfs stuff should probably go elsewhere later -john */
-static struct sys_device device_timer = {
-	.id	= 0,
-	.cls	= &timer_sysclass,
-};
-
-static int time_init_device(void)
-{
-	int error = sysdev_class_register(&timer_sysclass);
-	if (!error)
-		error = sysdev_register(&device_timer);
-	return error;
-}
-
-device_initcall(time_init_device);
diff --git a/arch/x86/kernel/tsc_64.c b/arch/x86/kernel/tsc_64.c
index 2a59bde..9f22e54 100644
--- a/arch/x86/kernel/tsc_64.c
+++ b/arch/x86/kernel/tsc_64.c
@@ -6,7 +6,9 @@
 #include <linux/time.h>
 #include <linux/acpi.h>
 #include <linux/cpufreq.h>
+#include <linux/acpi_pmtmr.h>
 
+#include <asm/hpet.h>
 #include <asm/timex.h>
 
 static int notsc __initdata = 0;
@@ -18,7 +20,7 @@
 
 static unsigned int cyc2ns_scale __read_mostly;
 
-void set_cyc2ns_scale(unsigned long khz)
+static inline void set_cyc2ns_scale(unsigned long khz)
 {
 	cyc2ns_scale = (NSEC_PER_MSEC << NS_SCALE) / khz;
 }
@@ -118,6 +120,95 @@
 
 #endif
 
+#define MAX_RETRIES	5
+#define SMI_TRESHOLD	50000
+
+/*
+ * Read TSC and the reference counters. Take care of SMI disturbance
+ */
+static unsigned long __init tsc_read_refs(unsigned long *pm,
+					  unsigned long *hpet)
+{
+	unsigned long t1, t2;
+	int i;
+
+	for (i = 0; i < MAX_RETRIES; i++) {
+		t1 = get_cycles_sync();
+		if (hpet)
+			*hpet = hpet_readl(HPET_COUNTER) & 0xFFFFFFFF;
+		else
+			*pm = acpi_pm_read_early();
+		t2 = get_cycles_sync();
+		if ((t2 - t1) < SMI_TRESHOLD)
+			return t2;
+	}
+	return ULONG_MAX;
+}
+
+/**
+ * tsc_calibrate - calibrate the tsc on boot
+ */
+void __init tsc_calibrate(void)
+{
+	unsigned long flags, tsc1, tsc2, tr1, tr2, pm1, pm2, hpet1, hpet2;
+	int hpet = is_hpet_enabled();
+
+	local_irq_save(flags);
+
+	tsc1 = tsc_read_refs(&pm1, hpet ? &hpet1 : NULL);
+
+	outb((inb(0x61) & ~0x02) | 0x01, 0x61);
+
+	outb(0xb0, 0x43);
+	outb((CLOCK_TICK_RATE / (1000 / 50)) & 0xff, 0x42);
+	outb((CLOCK_TICK_RATE / (1000 / 50)) >> 8, 0x42);
+	tr1 = get_cycles_sync();
+	while ((inb(0x61) & 0x20) == 0);
+	tr2 = get_cycles_sync();
+
+	tsc2 = tsc_read_refs(&pm2, hpet ? &hpet2 : NULL);
+
+	local_irq_restore(flags);
+
+	/*
+	 * Preset the result with the raw and inaccurate PIT
+	 * calibration value
+	 */
+	tsc_khz = (tr2 - tr1) / 50;
+
+	/* hpet or pmtimer available ? */
+	if (!hpet && !pm1 && !pm2) {
+		printk(KERN_INFO "TSC calibrated against PIT\n");
+		return;
+	}
+
+	/* Check, whether the sampling was disturbed by an SMI */
+	if (tsc1 == ULONG_MAX || tsc2 == ULONG_MAX) {
+		printk(KERN_WARNING "TSC calibration disturbed by SMI, "
+		       "using PIT calibration result\n");
+		return;
+	}
+
+	tsc2 = (tsc2 - tsc1) * 1000000L;
+
+	if (hpet) {
+		printk(KERN_INFO "TSC calibrated against HPET\n");
+		if (hpet2 < hpet1)
+			hpet2 += 0x100000000;
+		hpet2 -= hpet1;
+		tsc1 = (hpet2 * hpet_readl(HPET_PERIOD)) / 1000000;
+	} else {
+		printk(KERN_INFO "TSC calibrated against PM_TIMER\n");
+		if (pm2 < pm1)
+			pm2 += ACPI_PM_OVRRUN;
+		pm2 -= pm1;
+		tsc1 = (pm2 * 1000000000) / PMTMR_TICKS_PER_SEC;
+	}
+
+	tsc_khz = tsc2 / tsc1;
+	set_cyc2ns_scale(tsc_khz);
+}
+
 /*
  * Make an educated guess if the TSC is trustworthy and synchronized
  * over all CPUs.
diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig
index 04d324c..cf013cb 100644
--- a/arch/x86_64/Kconfig
+++ b/arch/x86_64/Kconfig
@@ -36,6 +36,18 @@
 	bool
 	default y
 
+config CLOCKSOURCE_WATCHDOG
+	bool
+	default y
+
+config GENERIC_CLOCKEVENTS
+	bool
+	default y
+
+config GENERIC_CLOCKEVENTS_BROADCAST
+	bool
+	default y
+
 config ZONE_DMA32
 	bool
 	default y
@@ -130,6 +142,8 @@
 
 menu "Processor type and features"
 
+source "kernel/time/Kconfig"
+
 choice
 	prompt "Subarchitecture Type"
 	default X86_PC
diff --git a/block/Kconfig b/block/Kconfig
index 2484e0e..e108956 100644
--- a/block/Kconfig
+++ b/block/Kconfig
@@ -62,6 +62,10 @@
 	protocols (e.g. Task Management Functions and SMP in Serial
 	Attached SCSI).
 
+config BLOCK_COMPAT
+	bool
+	default y
+
 endif # BLOCK
 
 source block/Kconfig.iosched
diff --git a/block/Makefile b/block/Makefile
index 3cfe7ce..8261081 100644
--- a/block/Makefile
+++ b/block/Makefile
@@ -11,4 +11,4 @@
 obj-$(CONFIG_IOSCHED_CFQ)	+= cfq-iosched.o
 
 obj-$(CONFIG_BLK_DEV_IO_TRACE)	+= blktrace.o
-obj-$(CONFIG_COMPAT)		+= compat_ioctl.o
+obj-$(CONFIG_BLOCK_COMPAT)	+= compat_ioctl.o
diff --git a/block/bsg.c b/block/bsg.c
index ed26468..b8ddfc6 100644
--- a/block/bsg.c
+++ b/block/bsg.c
@@ -1010,10 +1010,7 @@
 }
 EXPORT_SYMBOL_GPL(bsg_register_queue);
 
-static struct cdev bsg_cdev = {
-	.kobj   = {.name = "bsg", },
-	.owner  = THIS_MODULE,
-};
+static struct cdev bsg_cdev;
 
 static int __init bsg_init(void)
 {
diff --git a/block/elevator.c b/block/elevator.c
index c6d153d..b9c518a 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -186,7 +186,7 @@
 	eq->ops = &e->ops;
 	eq->elevator_type = e;
 	kobject_init(&eq->kobj);
-	snprintf(eq->kobj.name, KOBJ_NAME_LEN, "%s", "iosched");
+	kobject_set_name(&eq->kobj, "%s", "iosched");
 	eq->kobj.ktype = &elv_ktype;
 	mutex_init(&eq->sysfs_lock);
 
diff --git a/block/genhd.c b/block/genhd.c
index 3af1e7a..e609996 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -540,61 +540,42 @@
 	return ((ktype == &ktype_block) || (ktype == &ktype_part));
 }
 
-static int block_uevent(struct kset *kset, struct kobject *kobj, char **envp,
-			 int num_envp, char *buffer, int buffer_size)
+static int block_uevent(struct kset *kset, struct kobject *kobj,
+			struct kobj_uevent_env *env)
 {
 	struct kobj_type *ktype = get_ktype(kobj);
 	struct device *physdev;
 	struct gendisk *disk;
 	struct hd_struct *part;
-	int length = 0;
-	int i = 0;
 
 	if (ktype == &ktype_block) {
 		disk = container_of(kobj, struct gendisk, kobj);
-		add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
-			       &length, "MINOR=%u", disk->first_minor);
+		add_uevent_var(env, "MINOR=%u", disk->first_minor);
 	} else if (ktype == &ktype_part) {
 		disk = container_of(kobj->parent, struct gendisk, kobj);
 		part = container_of(kobj, struct hd_struct, kobj);
-		add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
-			       &length, "MINOR=%u",
+		add_uevent_var(env, "MINOR=%u",
 			       disk->first_minor + part->partno);
 	} else
 		return 0;
 
-	add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
-		       "MAJOR=%u", disk->major);
+	add_uevent_var(env, "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_uevent_var(envp, num_envp, &i, buffer, buffer_size,
-			       &length, "PHYSDEVPATH=%s", path);
+		add_uevent_var(env, "PHYSDEVPATH=%s", path);
 		kfree(path);
 
 		if (physdev->bus)
-			add_uevent_var(envp, num_envp, &i,
-				       buffer, buffer_size, &length,
-				       "PHYSDEVBUS=%s",
-				       physdev->bus->name);
+			add_uevent_var(env, "PHYSDEVBUS=%s", physdev->bus->name);
 
 		if (physdev->driver)
-			add_uevent_var(envp, num_envp, &i,
-				       buffer, buffer_size, &length,
-				       "PHYSDEVDRIVER=%s",
-				       physdev->driver->name);
+			add_uevent_var(env, 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;
 }
 
diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c
index cd9d2c5..d875673 100644
--- a/block/ll_rw_blk.c
+++ b/block/ll_rw_blk.c
@@ -1854,7 +1854,7 @@
 
 	init_timer(&q->unplug_timer);
 
-	snprintf(q->kobj.name, KOBJ_NAME_LEN, "%s", "queue");
+	kobject_set_name(&q->kobj, "%s", "queue");
 	q->kobj.ktype = &queue_ktype;
 	kobject_init(&q->kobj);
 
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index feab124..cbfc815 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -194,7 +194,7 @@
 
 	if (!device->flags.power_manageable) {
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n",
-				device->dev.kobj.name));
+				kobject_name(&device->dev.kobj)));
 		return -ENODEV;
 	}
 	/*
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 1e8287b..1f6fb38d 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -276,21 +276,12 @@
 
 static void acpi_propagate_timer_broadcast(struct acpi_processor *pr)
 {
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
 	unsigned long reason;
 
 	reason = pr->power.timer_broadcast_on_state < INT_MAX ?
 		CLOCK_EVT_NOTIFY_BROADCAST_ON : CLOCK_EVT_NOTIFY_BROADCAST_OFF;
 
 	clockevents_notify(reason, &pr->id);
-#else
-	cpumask_t mask = cpumask_of_cpu(pr->id);
-
-	if (pr->power.timer_broadcast_on_state < INT_MAX)
-		on_each_cpu(switch_APIC_timer_to_ipi, &mask, 1, 1);
-	else
-		on_each_cpu(switch_ipi_to_APIC_timer, &mask, 1, 1);
-#endif
 }
 
 /* Power(C) State timer broadcast control */
@@ -298,8 +289,6 @@
 				       struct acpi_processor_cx *cx,
 				       int broadcast)
 {
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
-
 	int state = cx - pr->power.states;
 
 	if (state >= pr->power.timer_broadcast_on_state) {
@@ -309,7 +298,6 @@
 			CLOCK_EVT_NOTIFY_BROADCAST_EXIT;
 		clockevents_notify(reason, &pr->id);
 	}
-#endif
 }
 
 #else
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 64620d6..5b4d462 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -319,16 +319,18 @@
 	return !acpi_match_device_ids(acpi_dev, acpi_drv->ids);
 }
 
-static int acpi_device_uevent(struct device *dev, char **envp, int num_envp,
-			      char *buffer, int buffer_size)
+static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct acpi_device *acpi_dev = to_acpi_device(dev);
+	int len;
 
-	strcpy(buffer, "MODALIAS=");
-	if (create_modalias(acpi_dev, buffer + 9, buffer_size - 9) > 0) {
-		envp[0] = buffer;
-		envp[1] = NULL;
-	}
+	if (add_uevent_var(env, "MODALIAS="))
+		return -ENOMEM;
+	len = create_modalias(acpi_dev, &env->buf[env->buflen - 1],
+			      sizeof(env->buf) - env->buflen);
+	if (len >= (sizeof(env->buf) - env->buflen))
+		return -ENOMEM;
+	env->buflen += len;
 	return 0;
 }
 
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index d05891f..b8a2095 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -316,7 +316,7 @@
 {
 	unsigned long state;
 	struct acpi_video_device *vd =
-		(struct acpi_video_device *)class_get_devdata(&od->class_dev);
+		(struct acpi_video_device *)dev_get_drvdata(&od->dev);
 	acpi_video_device_get_state(vd, &state);
 	return (int)state;
 }
@@ -325,7 +325,7 @@
 {
 	unsigned long state = od->request_state;
 	struct acpi_video_device *vd=
-		(struct acpi_video_device *)class_get_devdata(&od->class_dev);
+		(struct acpi_video_device *)dev_get_drvdata(&od->dev);
 	return acpi_video_device_set_state(vd, state);
 }
 
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
index 268e301..6b94fb7 100644
--- a/drivers/amba/bus.c
+++ b/drivers/amba/bus.c
@@ -44,15 +44,12 @@
 }
 
 #ifdef CONFIG_HOTPLUG
-static int amba_uevent(struct device *dev, char **envp, int nr_env, char *buf, int bufsz)
+static int amba_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct amba_device *pcdev = to_amba_device(dev);
-	int retval = 0, i = 0, len = 0;
+	int retval = 0;
 
-	retval = add_uevent_var(envp, nr_env, &i,
-				buf, bufsz, &len,
-				"AMBA_ID=%08x", pcdev->periphid);
-	envp[i] = NULL;
+	retval = add_uevent_var(env, "AMBA_ID=%08x", pcdev->periphid);
 	return retval;
 }
 #else
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index 5d6312e3..d7da109 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -1,5 +1,13 @@
 menu "Generic Driver Options"
 
+config UEVENT_HELPER_PATH
+	string "path to uevent helper"
+	depends on HOTPLUG
+	default "/sbin/hotplug"
+	help
+	  Path to uevent helper program forked by the kernel for
+	  every uevent.
+
 config STANDALONE
 	bool "Select only drivers that don't need compile-time external firmware" if EXPERIMENTAL
 	default y
diff --git a/drivers/base/base.h b/drivers/base/base.h
index 47eb02d..10b2fb6 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -18,8 +18,6 @@
 extern int bus_add_device(struct device * dev);
 extern void bus_attach_device(struct device * dev);
 extern void bus_remove_device(struct device * dev);
-extern struct bus_type *get_bus(struct bus_type * bus);
-extern void put_bus(struct bus_type * bus);
 
 extern int bus_add_driver(struct device_driver *);
 extern void bus_remove_driver(struct device_driver *);
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 61c6752..9a19b07 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -30,6 +30,17 @@
 static int __must_check bus_rescan_devices_helper(struct device *dev,
 						void *data);
 
+static struct bus_type *bus_get(struct bus_type *bus)
+{
+	return bus ? container_of(kset_get(&bus->subsys),
+				struct bus_type, subsys) : NULL;
+}
+
+static void bus_put(struct bus_type *bus)
+{
+	kset_put(&bus->subsys);
+}
+
 static ssize_t
 drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
 {
@@ -78,7 +89,7 @@
 	 */
 }
 
-static struct kobj_type ktype_driver = {
+static struct kobj_type driver_ktype = {
 	.sysfs_ops	= &driver_sysfs_ops,
 	.release	= driver_release,
 };
@@ -122,9 +133,9 @@
 int bus_create_file(struct bus_type * bus, struct bus_attribute * attr)
 {
 	int error;
-	if (get_bus(bus)) {
+	if (bus_get(bus)) {
 		error = sysfs_create_file(&bus->subsys.kobj, &attr->attr);
-		put_bus(bus);
+		bus_put(bus);
 	} else
 		error = -EINVAL;
 	return error;
@@ -132,9 +143,9 @@
 
 void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr)
 {
-	if (get_bus(bus)) {
+	if (bus_get(bus)) {
 		sysfs_remove_file(&bus->subsys.kobj, &attr->attr);
-		put_bus(bus);
+		bus_put(bus);
 	}
 }
 
@@ -172,7 +183,7 @@
 static ssize_t driver_unbind(struct device_driver *drv,
 			     const char *buf, size_t count)
 {
-	struct bus_type *bus = get_bus(drv->bus);
+	struct bus_type *bus = bus_get(drv->bus);
 	struct device *dev;
 	int err = -ENODEV;
 
@@ -186,7 +197,7 @@
 		err = count;
 	}
 	put_device(dev);
-	put_bus(bus);
+	bus_put(bus);
 	return err;
 }
 static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind);
@@ -199,7 +210,7 @@
 static ssize_t driver_bind(struct device_driver *drv,
 			   const char *buf, size_t count)
 {
-	struct bus_type *bus = get_bus(drv->bus);
+	struct bus_type *bus = bus_get(drv->bus);
 	struct device *dev;
 	int err = -ENODEV;
 
@@ -219,7 +230,7 @@
 			err = -ENODEV;
 	}
 	put_device(dev);
-	put_bus(bus);
+	bus_put(bus);
 	return err;
 }
 static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind);
@@ -430,7 +441,7 @@
  */
 int bus_add_device(struct device * dev)
 {
-	struct bus_type * bus = get_bus(dev->bus);
+	struct bus_type * bus = bus_get(dev->bus);
 	int error = 0;
 
 	if (bus) {
@@ -459,7 +470,7 @@
 out_id:
 	device_remove_attrs(bus, dev);
 out_put:
-	put_bus(dev->bus);
+	bus_put(dev->bus);
 	return error;
 }
 
@@ -509,7 +520,7 @@
 		}
 		pr_debug("bus %s: remove device %s\n", dev->bus->name, dev->bus_id);
 		device_release_driver(dev);
-		put_bus(dev->bus);
+		bus_put(dev->bus);
 	}
 }
 
@@ -568,32 +579,29 @@
 	driver_remove_file(drv, &driver_attr_unbind);
 }
 
+static BUS_ATTR(drivers_probe, S_IWUSR, NULL, store_drivers_probe);
+static BUS_ATTR(drivers_autoprobe, S_IWUSR | S_IRUGO,
+		show_drivers_autoprobe, store_drivers_autoprobe);
+
 static int add_probe_files(struct bus_type *bus)
 {
 	int retval;
 
-	bus->drivers_probe_attr.attr.name = "drivers_probe";
-	bus->drivers_probe_attr.attr.mode = S_IWUSR;
-	bus->drivers_probe_attr.store = store_drivers_probe;
-	retval = bus_create_file(bus, &bus->drivers_probe_attr);
+	retval = bus_create_file(bus, &bus_attr_drivers_probe);
 	if (retval)
 		goto out;
 
-	bus->drivers_autoprobe_attr.attr.name = "drivers_autoprobe";
-	bus->drivers_autoprobe_attr.attr.mode = S_IWUSR | S_IRUGO;
-	bus->drivers_autoprobe_attr.show = show_drivers_autoprobe;
-	bus->drivers_autoprobe_attr.store = store_drivers_autoprobe;
-	retval = bus_create_file(bus, &bus->drivers_autoprobe_attr);
+	retval = bus_create_file(bus, &bus_attr_drivers_autoprobe);
 	if (retval)
-		bus_remove_file(bus, &bus->drivers_probe_attr);
+		bus_remove_file(bus, &bus_attr_drivers_probe);
 out:
 	return retval;
 }
 
 static void remove_probe_files(struct bus_type *bus)
 {
-	bus_remove_file(bus, &bus->drivers_autoprobe_attr);
-	bus_remove_file(bus, &bus->drivers_probe_attr);
+	bus_remove_file(bus, &bus_attr_drivers_autoprobe);
+	bus_remove_file(bus, &bus_attr_drivers_probe);
 }
 #else
 static inline int add_bind_files(struct device_driver *drv) { return 0; }
@@ -602,6 +610,17 @@
 static inline void remove_probe_files(struct bus_type *bus) {}
 #endif
 
+static ssize_t driver_uevent_store(struct device_driver *drv,
+				   const char *buf, size_t count)
+{
+	enum kobject_action action;
+
+	if (kobject_action_type(buf, count, &action) == 0)
+		kobject_uevent(&drv->kobj, action);
+	return count;
+}
+static DRIVER_ATTR(uevent, S_IWUSR, NULL, driver_uevent_store);
+
 /**
  *	bus_add_driver - Add a driver to the bus.
  *	@drv:	driver.
@@ -609,7 +628,7 @@
  */
 int bus_add_driver(struct device_driver *drv)
 {
-	struct bus_type * bus = get_bus(drv->bus);
+	struct bus_type * bus = bus_get(drv->bus);
 	int error = 0;
 
 	if (!bus)
@@ -632,6 +651,11 @@
 	klist_add_tail(&drv->knode_bus, &bus->klist_drivers);
 	module_add_driver(drv->owner, drv);
 
+	error = driver_create_file(drv, &driver_attr_uevent);
+	if (error) {
+		printk(KERN_ERR "%s: uevent attr (%s) failed\n",
+			__FUNCTION__, drv->name);
+	}
 	error = driver_add_attrs(bus, drv);
 	if (error) {
 		/* How the hell do we get out of this pickle? Give up */
@@ -649,7 +673,7 @@
 out_unregister:
 	kobject_unregister(&drv->kobj);
 out_put_bus:
-	put_bus(bus);
+	bus_put(bus);
 	return error;
 }
 
@@ -669,12 +693,13 @@
 
 	remove_bind_files(drv);
 	driver_remove_attrs(drv->bus, drv);
+	driver_remove_file(drv, &driver_attr_uevent);
 	klist_remove(&drv->knode_bus);
 	pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name);
 	driver_detach(drv);
 	module_remove_driver(drv);
 	kobject_unregister(&drv->kobj);
-	put_bus(drv->bus);
+	bus_put(drv->bus);
 }
 
 
@@ -729,18 +754,6 @@
 }
 EXPORT_SYMBOL_GPL(device_reprobe);
 
-struct bus_type *get_bus(struct bus_type *bus)
-{
-	return bus ? container_of(subsys_get(&bus->subsys),
-				struct bus_type, subsys) : NULL;
-}
-
-void put_bus(struct bus_type * bus)
-{
-	subsys_put(&bus->subsys);
-}
-
-
 /**
  *	find_bus - locate bus by name.
  *	@name:	name of bus.
@@ -808,6 +821,17 @@
 	put_device(dev);
 }
 
+static ssize_t bus_uevent_store(struct bus_type *bus,
+				const char *buf, size_t count)
+{
+	enum kobject_action action;
+
+	if (kobject_action_type(buf, count, &action) == 0)
+		kobject_uevent(&bus->subsys.kobj, action);
+	return count;
+}
+static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store);
+
 /**
  *	bus_register - register a bus with the system.
  *	@bus:	bus.
@@ -826,11 +850,16 @@
 	if (retval)
 		goto out;
 
-	subsys_set_kset(bus, bus_subsys);
+	bus->subsys.kobj.kset = &bus_subsys;
+
 	retval = subsystem_register(&bus->subsys);
 	if (retval)
 		goto out;
 
+	retval = bus_create_file(bus, &bus_attr_uevent);
+	if (retval)
+		goto bus_uevent_fail;
+
 	kobject_set_name(&bus->devices.kobj, "devices");
 	bus->devices.kobj.parent = &bus->subsys.kobj;
 	retval = kset_register(&bus->devices);
@@ -839,7 +868,7 @@
 
 	kobject_set_name(&bus->drivers.kobj, "drivers");
 	bus->drivers.kobj.parent = &bus->subsys.kobj;
-	bus->drivers.ktype = &ktype_driver;
+	bus->drivers.ktype = &driver_ktype;
 	retval = kset_register(&bus->drivers);
 	if (retval)
 		goto bus_drivers_fail;
@@ -866,6 +895,8 @@
 bus_drivers_fail:
 	kset_unregister(&bus->devices);
 bus_devices_fail:
+	bus_remove_file(bus, &bus_attr_uevent);
+bus_uevent_fail:
 	subsystem_unregister(&bus->subsys);
 out:
 	return retval;
@@ -876,7 +907,7 @@
  *	@bus:	bus.
  *
  *	Unregister the child subsystems and the bus itself.
- *	Finally, we call put_bus() to release the refcount
+ *	Finally, we call bus_put() to release the refcount
  */
 void bus_unregister(struct bus_type * bus)
 {
@@ -885,6 +916,7 @@
 	remove_probe_files(bus);
 	kset_unregister(&bus->drivers);
 	kset_unregister(&bus->devices);
+	bus_remove_file(bus, &bus_attr_uevent);
 	subsystem_unregister(&bus->subsys);
 }
 
diff --git a/drivers/base/class.c b/drivers/base/class.c
index 4d22226..a863bb0 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -65,13 +65,13 @@
 	.store	= class_attr_store,
 };
 
-static struct kobj_type ktype_class = {
+static struct kobj_type class_ktype = {
 	.sysfs_ops	= &class_sysfs_ops,
 	.release	= class_release,
 };
 
 /* Hotplug events for classes go to the class_obj subsys */
-static decl_subsys(class, &ktype_class, NULL);
+static decl_subsys(class, &class_ktype, NULL);
 
 
 int class_create_file(struct class * cls, const struct class_attribute * attr)
@@ -93,14 +93,14 @@
 static struct class *class_get(struct class *cls)
 {
 	if (cls)
-		return container_of(subsys_get(&cls->subsys), struct class, subsys);
+		return container_of(kset_get(&cls->subsys), struct class, subsys);
 	return NULL;
 }
 
 static void class_put(struct class * cls)
 {
 	if (cls)
-		subsys_put(&cls->subsys);
+		kset_put(&cls->subsys);
 }
 
 
@@ -149,7 +149,7 @@
 	if (error)
 		return error;
 
-	subsys_set_kset(cls, class_subsys);
+	cls->subsys.kobj.kset = &class_subsys;
 
 	error = subsystem_register(&cls->subsys);
 	if (!error) {
@@ -180,8 +180,7 @@
 
 /* needed to allow these devices to have parent class devices */
 static int class_device_create_uevent(struct class_device *class_dev,
-				       char **envp, int num_envp,
-				       char *buffer, int buffer_size)
+				      struct kobj_uevent_env *env)
 {
 	pr_debug("%s called for %s\n", __FUNCTION__, class_dev->class_id);
 	return 0;
@@ -324,7 +323,7 @@
 	}
 }
 
-static struct kobj_type ktype_class_device = {
+static struct kobj_type class_device_ktype = {
 	.sysfs_ops	= &class_dev_sysfs_ops,
 	.release	= class_dev_release,
 };
@@ -333,7 +332,7 @@
 {
 	struct kobj_type *ktype = get_ktype(kobj);
 
-	if (ktype == &ktype_class_device) {
+	if (ktype == &class_device_ktype) {
 		struct class_device *class_dev = to_class_dev(kobj);
 		if (class_dev->class)
 			return 1;
@@ -403,64 +402,43 @@
 { }
 #endif
 
-static int class_uevent(struct kset *kset, struct kobject *kobj, char **envp,
-			 int num_envp, char *buffer, int buffer_size)
+static int class_uevent(struct kset *kset, struct kobject *kobj,
+			struct kobj_uevent_env *env)
 {
 	struct class_device *class_dev = to_class_dev(kobj);
 	struct device *dev = class_dev->dev;
-	int i = 0;
-	int length = 0;
 	int retval = 0;
 
 	pr_debug("%s - name = %s\n", __FUNCTION__, class_dev->class_id);
 
 	if (MAJOR(class_dev->devt)) {
-		add_uevent_var(envp, num_envp, &i,
-			       buffer, buffer_size, &length,
-			       "MAJOR=%u", MAJOR(class_dev->devt));
+		add_uevent_var(env, "MAJOR=%u", MAJOR(class_dev->devt));
 
-		add_uevent_var(envp, num_envp, &i,
-			       buffer, buffer_size, &length,
-			       "MINOR=%u", MINOR(class_dev->devt));
+		add_uevent_var(env, "MINOR=%u", MINOR(class_dev->devt));
 	}
 
 	if (dev) {
 		const char *path = kobject_get_path(&dev->kobj, GFP_KERNEL);
 		if (path) {
-			add_uevent_var(envp, num_envp, &i,
-				       buffer, buffer_size, &length,
-				       "PHYSDEVPATH=%s", path);
+			add_uevent_var(env, "PHYSDEVPATH=%s", path);
 			kfree(path);
 		}
 
 		if (dev->bus)
-			add_uevent_var(envp, num_envp, &i,
-				       buffer, buffer_size, &length,
-				       "PHYSDEVBUS=%s", dev->bus->name);
+			add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name);
 
 		if (dev->driver)
-			add_uevent_var(envp, num_envp, &i,
-				       buffer, buffer_size, &length,
-				       "PHYSDEVDRIVER=%s", dev->driver->name);
+			add_uevent_var(env, "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 (class_dev->uevent) {
 		/* have the class device specific function add its stuff */
-		retval = class_dev->uevent(class_dev, envp, num_envp,
-					    buffer, buffer_size);
+		retval = class_dev->uevent(class_dev, env);
 		if (retval)
 			pr_debug("class_dev->uevent() returned %d\n", retval);
 	} else if (class_dev->class->uevent) {
 		/* have the class specific function add its stuff */
-		retval = class_dev->class->uevent(class_dev, envp, num_envp,
-						   buffer, buffer_size);
+		retval = class_dev->class->uevent(class_dev, env);
 		if (retval)
 			pr_debug("class->uevent() returned %d\n", retval);
 	}
@@ -474,7 +452,7 @@
 	.uevent =	class_uevent,
 };
 
-static decl_subsys(class_obj, &ktype_class_device, &class_uevent_ops);
+static decl_subsys(class_obj, &class_device_ktype, &class_uevent_ops);
 
 
 static int class_device_add_attrs(struct class_device * cd)
@@ -883,7 +861,7 @@
 
 	/* ick, this is ugly, the things we go through to keep from showing up
 	 * in sysfs... */
-	subsystem_init(&class_obj_subsys);
+	kset_init(&class_obj_subsys);
 	if (!class_obj_subsys.kobj.parent)
 		class_obj_subsys.kobj.parent = &class_obj_subsys.kobj;
 	return 0;
diff --git a/drivers/base/core.c b/drivers/base/core.c
index ec86d6f..c134341 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -108,7 +108,7 @@
 	}
 }
 
-static struct kobj_type ktype_device = {
+static struct kobj_type device_ktype = {
 	.release	= device_release,
 	.sysfs_ops	= &dev_sysfs_ops,
 };
@@ -118,7 +118,7 @@
 {
 	struct kobj_type *ktype = get_ktype(kobj);
 
-	if (ktype == &ktype_device) {
+	if (ktype == &device_ktype) {
 		struct device *dev = to_dev(kobj);
 		if (dev->uevent_suppress)
 			return 0;
@@ -141,33 +141,23 @@
 	return NULL;
 }
 
-static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp,
-			int num_envp, char *buffer, int buffer_size)
+static int dev_uevent(struct kset *kset, struct kobject *kobj,
+		      struct kobj_uevent_env *env)
 {
 	struct device *dev = to_dev(kobj);
-	int i = 0;
-	int length = 0;
 	int retval = 0;
 
 	/* add the major/minor if present */
 	if (MAJOR(dev->devt)) {
-		add_uevent_var(envp, num_envp, &i,
-			       buffer, buffer_size, &length,
-			       "MAJOR=%u", MAJOR(dev->devt));
-		add_uevent_var(envp, num_envp, &i,
-			       buffer, buffer_size, &length,
-			       "MINOR=%u", MINOR(dev->devt));
+		add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt));
+		add_uevent_var(env, "MINOR=%u", MINOR(dev->devt));
 	}
 
 	if (dev->type && dev->type->name)
-		add_uevent_var(envp, num_envp, &i,
-			       buffer, buffer_size, &length,
-			       "DEVTYPE=%s", dev->type->name);
+		add_uevent_var(env, "DEVTYPE=%s", dev->type->name);
 
 	if (dev->driver)
-		add_uevent_var(envp, num_envp, &i,
-			       buffer, buffer_size, &length,
-			       "DRIVER=%s", dev->driver->name);
+		add_uevent_var(env, "DRIVER=%s", dev->driver->name);
 
 #ifdef CONFIG_SYSFS_DEPRECATED
 	if (dev->class) {
@@ -181,59 +171,43 @@
 
 			path = kobject_get_path(&parent->kobj, GFP_KERNEL);
 			if (path) {
-				add_uevent_var(envp, num_envp, &i,
-					       buffer, buffer_size, &length,
-					       "PHYSDEVPATH=%s", path);
+				add_uevent_var(env, "PHYSDEVPATH=%s", path);
 				kfree(path);
 			}
 
-			add_uevent_var(envp, num_envp, &i,
-				       buffer, buffer_size, &length,
-				       "PHYSDEVBUS=%s", parent->bus->name);
+			add_uevent_var(env, "PHYSDEVBUS=%s", parent->bus->name);
 
 			if (parent->driver)
-				add_uevent_var(envp, num_envp, &i,
-					       buffer, buffer_size, &length,
-					       "PHYSDEVDRIVER=%s", parent->driver->name);
+				add_uevent_var(env, "PHYSDEVDRIVER=%s",
+					       parent->driver->name);
 		}
 	} else if (dev->bus) {
-		add_uevent_var(envp, num_envp, &i,
-			       buffer, buffer_size, &length,
-			       "PHYSDEVBUS=%s", dev->bus->name);
+		add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name);
 
 		if (dev->driver)
-			add_uevent_var(envp, num_envp, &i,
-				       buffer, buffer_size, &length,
-				       "PHYSDEVDRIVER=%s", dev->driver->name);
+			add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name);
 	}
 #endif
 
-	/* terminate, set to next free slot, shrink available space */
-	envp[i] = NULL;
-	envp = &envp[i];
-	num_envp -= i;
-	buffer = &buffer[length];
-	buffer_size -= length;
-
+	/* have the bus specific function add its stuff */
 	if (dev->bus && dev->bus->uevent) {
-		/* have the bus specific function add its stuff */
-		retval = dev->bus->uevent(dev, envp, num_envp, buffer, buffer_size);
+		retval = dev->bus->uevent(dev, env);
 		if (retval)
 			pr_debug ("%s: bus uevent() returned %d\n",
 				  __FUNCTION__, retval);
 	}
 
+	/* have the class specific function add its stuff */
 	if (dev->class && dev->class->dev_uevent) {
-		/* have the class specific function add its stuff */
-		retval = dev->class->dev_uevent(dev, envp, num_envp, buffer, buffer_size);
+		retval = dev->class->dev_uevent(dev, env);
 		if (retval)
 			pr_debug("%s: class uevent() returned %d\n",
 				 __FUNCTION__, retval);
 	}
 
+	/* have the device type specific fuction add its stuff */
 	if (dev->type && dev->type->uevent) {
-		/* have the device type specific fuction add its stuff */
-		retval = dev->type->uevent(dev, envp, num_envp, buffer, buffer_size);
+		retval = dev->type->uevent(dev, env);
 		if (retval)
 			pr_debug("%s: dev_type uevent() returned %d\n",
 				 __FUNCTION__, retval);
@@ -253,22 +227,18 @@
 {
 	struct kobject *top_kobj;
 	struct kset *kset;
-	char *envp[32];
-	char *data = NULL;
-	char *pos;
+	struct kobj_uevent_env *env = NULL;
 	int i;
 	size_t count = 0;
 	int retval;
 
 	/* search the kset, the device belongs to */
 	top_kobj = &dev->kobj;
-	if (!top_kobj->kset && top_kobj->parent) {
-		do {
-			top_kobj = top_kobj->parent;
-		} while (!top_kobj->kset && top_kobj->parent);
-	}
+	while (!top_kobj->kset && top_kobj->parent)
+		top_kobj = top_kobj->parent;
 	if (!top_kobj->kset)
 		goto out;
+
 	kset = top_kobj->kset;
 	if (!kset->uevent_ops || !kset->uevent_ops->uevent)
 		goto out;
@@ -278,43 +248,29 @@
 		if (!kset->uevent_ops->filter(kset, &dev->kobj))
 			goto out;
 
-	data = (char *)get_zeroed_page(GFP_KERNEL);
-	if (!data)
+	env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
+	if (!env)
 		return -ENOMEM;
 
 	/* let the kset specific function add its keys */
-	pos = data;
-	memset(envp, 0, sizeof(envp));
-	retval = kset->uevent_ops->uevent(kset, &dev->kobj,
-					  envp, ARRAY_SIZE(envp),
-					  pos, PAGE_SIZE);
+	retval = kset->uevent_ops->uevent(kset, &dev->kobj, env);
 	if (retval)
 		goto out;
 
 	/* copy keys to file */
-	for (i = 0; envp[i]; i++) {
-		pos = &buf[count];
-		count += sprintf(pos, "%s\n", envp[i]);
-	}
+	for (i = 0; i < env->envp_idx; i++)
+		count += sprintf(&buf[count], "%s\n", env->envp[i]);
 out:
-	free_page((unsigned long)data);
+	kfree(env);
 	return count;
 }
 
 static ssize_t store_uevent(struct device *dev, struct device_attribute *attr,
 			    const char *buf, size_t count)
 {
-	size_t len = count;
 	enum kobject_action action;
 
-	if (len && buf[len-1] == '\n')
-		len--;
-
-	for (action = 0; action < KOBJ_MAX; action++) {
-		if (strncmp(kobject_actions[action], buf, len) != 0)
-			continue;
-		if (kobject_actions[action][len] != '\0')
-			continue;
+	if (kobject_action_type(buf, count, &action) == 0) {
 		kobject_uevent(&dev->kobj, action);
 		goto out;
 	}
@@ -449,7 +405,7 @@
  *	devices_subsys - structure to be registered with kobject core.
  */
 
-decl_subsys(devices, &ktype_device, &device_uevent_ops);
+decl_subsys(devices, &device_ktype, &device_uevent_ops);
 
 
 /**
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index b24efd4..0295855 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -88,19 +88,14 @@
 
 static void fw_dev_release(struct device *dev);
 
-static int firmware_uevent(struct device *dev, char **envp, int num_envp,
-			   char *buffer, int buffer_size)
+static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct firmware_priv *fw_priv = dev_get_drvdata(dev);
-	int i = 0, len = 0;
 
-	if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
-			   "FIRMWARE=%s", fw_priv->fw_id))
+	if (add_uevent_var(env, "FIRMWARE=%s", fw_priv->fw_id))
 		return -ENOMEM;
-	if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
-			   "TIMEOUT=%i", loading_timeout))
+	if (add_uevent_var(env, "TIMEOUT=%i", loading_timeout))
 		return -ENOMEM;
-	envp[i] = NULL;
 
 	return 0;
 }
@@ -297,8 +292,7 @@
 
 static inline void fw_setup_device_id(struct device *f_dev, struct device *dev)
 {
-	/* XXX warning we should watch out for name collisions */
-	strlcpy(f_dev->bus_id, dev->bus_id, BUS_ID_SIZE);
+	snprintf(f_dev->bus_id, BUS_ID_SIZE, "firmware-%s", dev->bus_id);
 }
 
 static int fw_register_device(struct device **dev_p, const char *fw_name,
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 74b9679..cb99dae 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -34,8 +34,7 @@
 	return MEMORY_CLASS_NAME;
 }
 
-static int memory_uevent(struct kset *kset, struct kobject *kobj, char **envp,
-			int num_envp, char *buffer, int buffer_size)
+static int memory_uevent(struct kset *kset, struct kobj_uevent_env *env)
 {
 	int retval = 0;
 
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 869ff8c..fb56092 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -160,13 +160,8 @@
  *
  *	Create a platform device object which can have other objects attached
  *	to it, and which will have attached objects freed when it is released.
- *
- *	This device will be marked as not supporting hotpluggable drivers; no
- *	device add/remove uevents will be generated.  In the unusual case that
- *	the device isn't being dynamically allocated as a legacy "probe the
- *	hardware" driver, infrastructure code should reverse this marking.
  */
-struct platform_device *platform_device_alloc(const char *name, unsigned int id)
+struct platform_device *platform_device_alloc(const char *name, int id)
 {
 	struct platform_object *pa;
 
@@ -177,12 +172,6 @@
 		pa->pdev.id = id;
 		device_initialize(&pa->pdev.dev);
 		pa->pdev.dev.release = platform_device_release;
-
-		/* prevent hotplug "modprobe $(MODALIAS)" from causing trouble in
-		 * legacy probe-the-hardware drivers, which don't properly split
-		 * out device enumeration logic from drivers.
-		 */
-		pa->pdev.dev.uevent_suppress = 1;
 	}
 
 	return pa ? &pa->pdev : NULL;
@@ -256,7 +245,8 @@
 	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.%d", pdev->name,
+			 pdev->id);
 	else
 		strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE);
 
@@ -370,7 +360,7 @@
  *	the Linux driver model.  In particular, when such drivers are built
  *	as modules, they can't be "hotplugged".
  */
-struct platform_device *platform_device_register_simple(char *name, unsigned int id,
+struct platform_device *platform_device_register_simple(char *name, int id,
 							struct resource *res, unsigned int num)
 {
 	struct platform_device *pdev;
@@ -530,7 +520,7 @@
 modalias_show(struct device *dev, struct device_attribute *a, char *buf)
 {
 	struct platform_device	*pdev = to_platform_device(dev);
-	int len = snprintf(buf, PAGE_SIZE, "%s\n", pdev->name);
+	int len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name);
 
 	return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
 }
@@ -540,13 +530,11 @@
 	__ATTR_NULL,
 };
 
-static int platform_uevent(struct device *dev, char **envp, int num_envp,
-		char *buffer, int buffer_size)
+static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct platform_device	*pdev = to_platform_device(dev);
 
-	envp[0] = buffer;
-	snprintf(buffer, buffer_size, "MODALIAS=%s", pdev->name);
+	add_uevent_var(env, "MODALIAS=platform:%s", pdev->name);
 	return 0;
 }
 
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile
index 9caeaea..a803733 100644
--- a/drivers/base/power/Makefile
+++ b/drivers/base/power/Makefile
@@ -1,5 +1,5 @@
 obj-y			:= shutdown.o
-obj-$(CONFIG_PM_SLEEP)	+= main.o suspend.o resume.o sysfs.o
+obj-$(CONFIG_PM_SLEEP)	+= main.o sysfs.o
 obj-$(CONFIG_PM_TRACE)	+= trace.o
 
 ifeq ($(CONFIG_DEBUG_DRIVER),y)
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index eb9f38d..0ab4ab2 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -20,19 +20,24 @@
  */
 
 #include <linux/device.h>
+#include <linux/kallsyms.h>
 #include <linux/mutex.h>
+#include <linux/pm.h>
+#include <linux/resume-trace.h>
 
+#include "../base.h"
 #include "power.h"
 
 LIST_HEAD(dpm_active);
-LIST_HEAD(dpm_off);
-LIST_HEAD(dpm_off_irq);
+static LIST_HEAD(dpm_off);
+static LIST_HEAD(dpm_off_irq);
 
-DEFINE_MUTEX(dpm_mtx);
-DEFINE_MUTEX(dpm_list_mtx);
+static DEFINE_MUTEX(dpm_mtx);
+static DEFINE_MUTEX(dpm_list_mtx);
 
 int (*platform_enable_wakeup)(struct device *dev, int is_on);
 
+
 int device_pm_add(struct device *dev)
 {
 	int error;
@@ -61,3 +66,334 @@
 }
 
 
+/*------------------------- Resume routines -------------------------*/
+
+/**
+ *	resume_device - Restore state for one device.
+ *	@dev:	Device.
+ *
+ */
+
+static int resume_device(struct device * dev)
+{
+	int error = 0;
+
+	TRACE_DEVICE(dev);
+	TRACE_RESUME(0);
+
+	down(&dev->sem);
+
+	if (dev->bus && dev->bus->resume) {
+		dev_dbg(dev,"resuming\n");
+		error = dev->bus->resume(dev);
+	}
+
+	if (!error && dev->type && dev->type->resume) {
+		dev_dbg(dev,"resuming\n");
+		error = dev->type->resume(dev);
+	}
+
+	if (!error && dev->class && dev->class->resume) {
+		dev_dbg(dev,"class resume\n");
+		error = dev->class->resume(dev);
+	}
+
+	up(&dev->sem);
+
+	TRACE_RESUME(error);
+	return error;
+}
+
+
+static int resume_device_early(struct device * dev)
+{
+	int error = 0;
+
+	TRACE_DEVICE(dev);
+	TRACE_RESUME(0);
+	if (dev->bus && dev->bus->resume_early) {
+		dev_dbg(dev,"EARLY resume\n");
+		error = dev->bus->resume_early(dev);
+	}
+	TRACE_RESUME(error);
+	return error;
+}
+
+/*
+ * Resume the devices that have either not gone through
+ * the late suspend, or that did go through it but also
+ * went through the early resume
+ */
+static void dpm_resume(void)
+{
+	mutex_lock(&dpm_list_mtx);
+	while(!list_empty(&dpm_off)) {
+		struct list_head * entry = dpm_off.next;
+		struct device * dev = to_device(entry);
+
+		get_device(dev);
+		list_move_tail(entry, &dpm_active);
+
+		mutex_unlock(&dpm_list_mtx);
+		resume_device(dev);
+		mutex_lock(&dpm_list_mtx);
+		put_device(dev);
+	}
+	mutex_unlock(&dpm_list_mtx);
+}
+
+
+/**
+ *	device_resume - Restore state of each device in system.
+ *
+ *	Walk the dpm_off list, remove each entry, resume the device,
+ *	then add it to the dpm_active list.
+ */
+
+void device_resume(void)
+{
+	might_sleep();
+	mutex_lock(&dpm_mtx);
+	dpm_resume();
+	mutex_unlock(&dpm_mtx);
+}
+
+EXPORT_SYMBOL_GPL(device_resume);
+
+
+/**
+ *	dpm_power_up - Power on some devices.
+ *
+ *	Walk the dpm_off_irq list and power each device up. This
+ *	is used for devices that required they be powered down with
+ *	interrupts disabled. As devices are powered on, they are moved
+ *	to the dpm_active list.
+ *
+ *	Interrupts must be disabled when calling this.
+ */
+
+static void dpm_power_up(void)
+{
+	while(!list_empty(&dpm_off_irq)) {
+		struct list_head * entry = dpm_off_irq.next;
+		struct device * dev = to_device(entry);
+
+		list_move_tail(entry, &dpm_off);
+		resume_device_early(dev);
+	}
+}
+
+
+/**
+ *	device_power_up - Turn on all devices that need special attention.
+ *
+ *	Power on system devices then devices that required we shut them down
+ *	with interrupts disabled.
+ *	Called with interrupts disabled.
+ */
+
+void device_power_up(void)
+{
+	sysdev_resume();
+	dpm_power_up();
+}
+
+EXPORT_SYMBOL_GPL(device_power_up);
+
+
+/*------------------------- Suspend routines -------------------------*/
+
+/*
+ * The entries in the dpm_active list are in a depth first order, simply
+ * because children are guaranteed to be discovered after parents, and
+ * are inserted at the back of the list on discovery.
+ *
+ * All list on the suspend path are done in reverse order, so we operate
+ * on the leaves of the device tree (or forests, depending on how you want
+ * to look at it ;) first. As nodes are removed from the back of the list,
+ * they are inserted into the front of their destintation lists.
+ *
+ * Things are the reverse on the resume path - iterations are done in
+ * forward order, and nodes are inserted at the back of their destination
+ * lists. This way, the ancestors will be accessed before their descendents.
+ */
+
+static inline char *suspend_verb(u32 event)
+{
+	switch (event) {
+	case PM_EVENT_SUSPEND:	return "suspend";
+	case PM_EVENT_FREEZE:	return "freeze";
+	case PM_EVENT_PRETHAW:	return "prethaw";
+	default:		return "(unknown suspend event)";
+	}
+}
+
+
+static void
+suspend_device_dbg(struct device *dev, pm_message_t state, char *info)
+{
+	dev_dbg(dev, "%s%s%s\n", info, suspend_verb(state.event),
+		((state.event == PM_EVENT_SUSPEND) && device_may_wakeup(dev)) ?
+		", may wakeup" : "");
+}
+
+/**
+ *	suspend_device - Save state of one device.
+ *	@dev:	Device.
+ *	@state:	Power state device is entering.
+ */
+
+static int suspend_device(struct device * dev, pm_message_t state)
+{
+	int error = 0;
+
+	down(&dev->sem);
+	if (dev->power.power_state.event) {
+		dev_dbg(dev, "PM: suspend %d-->%d\n",
+			dev->power.power_state.event, state.event);
+	}
+
+	if (dev->class && dev->class->suspend) {
+		suspend_device_dbg(dev, state, "class ");
+		error = dev->class->suspend(dev, state);
+		suspend_report_result(dev->class->suspend, error);
+	}
+
+	if (!error && dev->type && dev->type->suspend) {
+		suspend_device_dbg(dev, state, "type ");
+		error = dev->type->suspend(dev, state);
+		suspend_report_result(dev->type->suspend, error);
+	}
+
+	if (!error && dev->bus && dev->bus->suspend) {
+		suspend_device_dbg(dev, state, "");
+		error = dev->bus->suspend(dev, state);
+		suspend_report_result(dev->bus->suspend, error);
+	}
+	up(&dev->sem);
+	return error;
+}
+
+
+/*
+ * This is called with interrupts off, only a single CPU
+ * running. We can't acquire a mutex or semaphore (and we don't
+ * need the protection)
+ */
+static int suspend_device_late(struct device *dev, pm_message_t state)
+{
+	int error = 0;
+
+	if (dev->bus && dev->bus->suspend_late) {
+		suspend_device_dbg(dev, state, "LATE ");
+		error = dev->bus->suspend_late(dev, state);
+		suspend_report_result(dev->bus->suspend_late, error);
+	}
+	return error;
+}
+
+/**
+ *	device_suspend - Save state and stop all devices in system.
+ *	@state:		Power state to put each device in.
+ *
+ *	Walk the dpm_active list, call ->suspend() for each device, and move
+ *	it to the dpm_off list.
+ *
+ *	(For historical reasons, if it returns -EAGAIN, that used to mean
+ *	that the device would be called again with interrupts disabled.
+ *	These days, we use the "suspend_late()" callback for that, so we
+ *	print a warning and consider it an error).
+ *
+ *	If we get a different error, try and back out.
+ *
+ *	If we hit a failure with any of the devices, call device_resume()
+ *	above to bring the suspended devices back to life.
+ *
+ */
+
+int device_suspend(pm_message_t state)
+{
+	int error = 0;
+
+	might_sleep();
+	mutex_lock(&dpm_mtx);
+	mutex_lock(&dpm_list_mtx);
+	while (!list_empty(&dpm_active) && error == 0) {
+		struct list_head * entry = dpm_active.prev;
+		struct device * dev = to_device(entry);
+
+		get_device(dev);
+		mutex_unlock(&dpm_list_mtx);
+
+		error = suspend_device(dev, state);
+
+		mutex_lock(&dpm_list_mtx);
+
+		/* Check if the device got removed */
+		if (!list_empty(&dev->power.entry)) {
+			/* Move it to the dpm_off list */
+			if (!error)
+				list_move(&dev->power.entry, &dpm_off);
+		}
+		if (error)
+			printk(KERN_ERR "Could not suspend device %s: "
+				"error %d%s\n",
+				kobject_name(&dev->kobj), error,
+				error == -EAGAIN ? " (please convert to suspend_late)" : "");
+		put_device(dev);
+	}
+	mutex_unlock(&dpm_list_mtx);
+	if (error)
+		dpm_resume();
+
+	mutex_unlock(&dpm_mtx);
+	return error;
+}
+
+EXPORT_SYMBOL_GPL(device_suspend);
+
+/**
+ *	device_power_down - Shut down special devices.
+ *	@state:		Power state to enter.
+ *
+ *	Walk the dpm_off_irq list, calling ->power_down() for each device that
+ *	couldn't power down the device with interrupts enabled. When we're
+ *	done, power down system devices.
+ */
+
+int device_power_down(pm_message_t state)
+{
+	int error = 0;
+	struct device * dev;
+
+	while (!list_empty(&dpm_off)) {
+		struct list_head * entry = dpm_off.prev;
+
+		dev = to_device(entry);
+		error = suspend_device_late(dev, state);
+		if (error)
+			goto Error;
+		list_move(&dev->power.entry, &dpm_off_irq);
+	}
+
+	error = sysdev_suspend(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;
+}
+
+EXPORT_SYMBOL_GPL(device_power_down);
+
+void __suspend_report_result(const char *function, void *fn, int ret)
+{
+	if (ret) {
+		printk(KERN_ERR "%s(): ", function);
+		print_fn_descriptor_symbol("%s() returns ", (unsigned long)fn);
+		printk("%d\n", ret);
+	}
+}
+EXPORT_SYMBOL_GPL(__suspend_report_result);
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
index 8ba0830..5c4efd4 100644
--- a/drivers/base/power/power.h
+++ b/drivers/base/power/power.h
@@ -11,32 +11,11 @@
  * main.c
  */
 
-/*
- * Used to synchronize global power management operations.
- */
-extern struct mutex dpm_mtx;
-
-/*
- * Used to serialize changes to the dpm_* lists.
- */
-extern struct mutex dpm_list_mtx;
-
-/*
- * The PM lists.
- */
-extern struct list_head dpm_active;
-extern struct list_head dpm_off;
-extern struct list_head dpm_off_irq;
-
-
-static inline struct dev_pm_info * to_pm_info(struct list_head * entry)
-{
-	return container_of(entry, struct dev_pm_info, entry);
-}
+extern struct list_head dpm_active;	/* The active device list */
 
 static inline struct device * to_device(struct list_head * entry)
 {
-	return container_of(to_pm_info(entry), struct device, power);
+	return container_of(entry, struct device, power.entry);
 }
 
 extern int device_pm_add(struct device *);
@@ -49,19 +28,6 @@
 extern int dpm_sysfs_add(struct device *);
 extern void dpm_sysfs_remove(struct device *);
 
-/*
- * resume.c
- */
-
-extern void dpm_resume(void);
-extern void dpm_power_up(void);
-extern int resume_device(struct device *);
-
-/*
- * suspend.c
- */
-extern int suspend_device(struct device *, pm_message_t);
-
 #else /* CONFIG_PM_SLEEP */
 
 
diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c
deleted file mode 100644
index 00fd84a..0000000
--- a/drivers/base/power/resume.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * resume.c - Functions for waking devices up.
- *
- * Copyright (c) 2003 Patrick Mochel
- * Copyright (c) 2003 Open Source Development Labs
- *
- * This file is released under the GPLv2
- *
- */
-
-#include <linux/device.h>
-#include <linux/resume-trace.h>
-#include "../base.h"
-#include "power.h"
-
-
-/**
- *	resume_device - Restore state for one device.
- *	@dev:	Device.
- *
- */
-
-int resume_device(struct device * dev)
-{
-	int error = 0;
-
-	TRACE_DEVICE(dev);
-	TRACE_RESUME(0);
-
-	down(&dev->sem);
-
-	if (dev->bus && dev->bus->resume) {
-		dev_dbg(dev,"resuming\n");
-		error = dev->bus->resume(dev);
-	}
-
-	if (!error && dev->type && dev->type->resume) {
-		dev_dbg(dev,"resuming\n");
-		error = dev->type->resume(dev);
-	}
-
-	if (!error && dev->class && dev->class->resume) {
-		dev_dbg(dev,"class resume\n");
-		error = dev->class->resume(dev);
-	}
-
-	up(&dev->sem);
-
-	TRACE_RESUME(error);
-	return error;
-}
-
-
-static int resume_device_early(struct device * dev)
-{
-	int error = 0;
-
-	TRACE_DEVICE(dev);
-	TRACE_RESUME(0);
-	if (dev->bus && dev->bus->resume_early) {
-		dev_dbg(dev,"EARLY resume\n");
-		error = dev->bus->resume_early(dev);
-	}
-	TRACE_RESUME(error);
-	return error;
-}
-
-/*
- * Resume the devices that have either not gone through
- * the late suspend, or that did go through it but also
- * went through the early resume
- */
-void dpm_resume(void)
-{
-	mutex_lock(&dpm_list_mtx);
-	while(!list_empty(&dpm_off)) {
-		struct list_head * entry = dpm_off.next;
-		struct device * dev = to_device(entry);
-
-		get_device(dev);
-		list_move_tail(entry, &dpm_active);
-
-		mutex_unlock(&dpm_list_mtx);
-		resume_device(dev);
-		mutex_lock(&dpm_list_mtx);
-		put_device(dev);
-	}
-	mutex_unlock(&dpm_list_mtx);
-}
-
-
-/**
- *	device_resume - Restore state of each device in system.
- *
- *	Walk the dpm_off list, remove each entry, resume the device,
- *	then add it to the dpm_active list.
- */
-
-void device_resume(void)
-{
-	might_sleep();
-	mutex_lock(&dpm_mtx);
-	dpm_resume();
-	mutex_unlock(&dpm_mtx);
-}
-
-EXPORT_SYMBOL_GPL(device_resume);
-
-
-/**
- *	dpm_power_up - Power on some devices.
- *
- *	Walk the dpm_off_irq list and power each device up. This
- *	is used for devices that required they be powered down with
- *	interrupts disabled. As devices are powered on, they are moved
- *	to the dpm_active list.
- *
- *	Interrupts must be disabled when calling this.
- */
-
-void dpm_power_up(void)
-{
-	while(!list_empty(&dpm_off_irq)) {
-		struct list_head * entry = dpm_off_irq.next;
-		struct device * dev = to_device(entry);
-
-		list_move_tail(entry, &dpm_off);
-		resume_device_early(dev);
-	}
-}
-
-
-/**
- *	device_power_up - Turn on all devices that need special attention.
- *
- *	Power on system devices then devices that required we shut them down
- *	with interrupts disabled.
- *	Called with interrupts disabled.
- */
-
-void device_power_up(void)
-{
-	sysdev_resume();
-	dpm_power_up();
-}
-
-EXPORT_SYMBOL_GPL(device_power_up);
-
-
diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c
deleted file mode 100644
index 26df9b2..0000000
--- a/drivers/base/power/suspend.c
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * suspend.c - Functions for putting devices to sleep.
- *
- * Copyright (c) 2003 Patrick Mochel
- * Copyright (c) 2003 Open Source Development Labs
- *
- * This file is released under the GPLv2
- *
- */
-
-#include <linux/device.h>
-#include <linux/kallsyms.h>
-#include <linux/pm.h>
-#include "../base.h"
-#include "power.h"
-
-/*
- * The entries in the dpm_active list are in a depth first order, simply
- * because children are guaranteed to be discovered after parents, and
- * are inserted at the back of the list on discovery.
- *
- * All list on the suspend path are done in reverse order, so we operate
- * on the leaves of the device tree (or forests, depending on how you want
- * to look at it ;) first. As nodes are removed from the back of the list,
- * they are inserted into the front of their destintation lists.
- *
- * Things are the reverse on the resume path - iterations are done in
- * forward order, and nodes are inserted at the back of their destination
- * lists. This way, the ancestors will be accessed before their descendents.
- */
-
-static inline char *suspend_verb(u32 event)
-{
-	switch (event) {
-	case PM_EVENT_SUSPEND:	return "suspend";
-	case PM_EVENT_FREEZE:	return "freeze";
-	case PM_EVENT_PRETHAW:	return "prethaw";
-	default:		return "(unknown suspend event)";
-	}
-}
-
-
-static void
-suspend_device_dbg(struct device *dev, pm_message_t state, char *info)
-{
-	dev_dbg(dev, "%s%s%s\n", info, suspend_verb(state.event),
-		((state.event == PM_EVENT_SUSPEND) && device_may_wakeup(dev)) ?
-		", may wakeup" : "");
-}
-
-/**
- *	suspend_device - Save state of one device.
- *	@dev:	Device.
- *	@state:	Power state device is entering.
- */
-
-int suspend_device(struct device * dev, pm_message_t state)
-{
-	int error = 0;
-
-	down(&dev->sem);
-	if (dev->power.power_state.event) {
-		dev_dbg(dev, "PM: suspend %d-->%d\n",
-			dev->power.power_state.event, state.event);
-	}
-
-	if (dev->class && dev->class->suspend) {
-		suspend_device_dbg(dev, state, "class ");
-		error = dev->class->suspend(dev, state);
-		suspend_report_result(dev->class->suspend, error);
-	}
-
-	if (!error && dev->type && dev->type->suspend) {
-		suspend_device_dbg(dev, state, "type ");
-		error = dev->type->suspend(dev, state);
-		suspend_report_result(dev->type->suspend, error);
-	}
-
-	if (!error && dev->bus && dev->bus->suspend) {
-		suspend_device_dbg(dev, state, "");
-		error = dev->bus->suspend(dev, state);
-		suspend_report_result(dev->bus->suspend, error);
-	}
-	up(&dev->sem);
-	return error;
-}
-
-
-/*
- * This is called with interrupts off, only a single CPU
- * running. We can't acquire a mutex or semaphore (and we don't
- * need the protection)
- */
-static int suspend_device_late(struct device *dev, pm_message_t state)
-{
-	int error = 0;
-
-	if (dev->bus && dev->bus->suspend_late) {
-		suspend_device_dbg(dev, state, "LATE ");
-		error = dev->bus->suspend_late(dev, state);
-		suspend_report_result(dev->bus->suspend_late, error);
-	}
-	return error;
-}
-
-/**
- *	device_suspend - Save state and stop all devices in system.
- *	@state:		Power state to put each device in.
- *
- *	Walk the dpm_active list, call ->suspend() for each device, and move
- *	it to the dpm_off list.
- *
- *	(For historical reasons, if it returns -EAGAIN, that used to mean
- *	that the device would be called again with interrupts disabled.
- *	These days, we use the "suspend_late()" callback for that, so we
- *	print a warning and consider it an error).
- *
- *	If we get a different error, try and back out.
- *
- *	If we hit a failure with any of the devices, call device_resume()
- *	above to bring the suspended devices back to life.
- *
- */
-
-int device_suspend(pm_message_t state)
-{
-	int error = 0;
-
-	might_sleep();
-	mutex_lock(&dpm_mtx);
-	mutex_lock(&dpm_list_mtx);
-	while (!list_empty(&dpm_active) && error == 0) {
-		struct list_head * entry = dpm_active.prev;
-		struct device * dev = to_device(entry);
-
-		get_device(dev);
-		mutex_unlock(&dpm_list_mtx);
-
-		error = suspend_device(dev, state);
-
-		mutex_lock(&dpm_list_mtx);
-
-		/* Check if the device got removed */
-		if (!list_empty(&dev->power.entry)) {
-			/* Move it to the dpm_off list */
-			if (!error)
-				list_move(&dev->power.entry, &dpm_off);
-		}
-		if (error)
-			printk(KERN_ERR "Could not suspend device %s: "
-				"error %d%s\n",
-				kobject_name(&dev->kobj), error,
-				error == -EAGAIN ? " (please convert to suspend_late)" : "");
-		put_device(dev);
-	}
-	mutex_unlock(&dpm_list_mtx);
-	if (error)
-		dpm_resume();
-
-	mutex_unlock(&dpm_mtx);
-	return error;
-}
-
-EXPORT_SYMBOL_GPL(device_suspend);
-
-/**
- *	device_power_down - Shut down special devices.
- *	@state:		Power state to enter.
- *
- *	Walk the dpm_off_irq list, calling ->power_down() for each device that
- *	couldn't power down the device with interrupts enabled. When we're
- *	done, power down system devices.
- */
-
-int device_power_down(pm_message_t state)
-{
-	int error = 0;
-	struct device * dev;
-
-	while (!list_empty(&dpm_off)) {
-		struct list_head * entry = dpm_off.prev;
-
-		dev = to_device(entry);
-		error = suspend_device_late(dev, state);
-		if (error)
-			goto Error;
-		list_move(&dev->power.entry, &dpm_off_irq);
-	}
-
-	error = sysdev_suspend(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;
-}
-
-EXPORT_SYMBOL_GPL(device_power_down);
-
-void __suspend_report_result(const char *function, void *fn, int ret)
-{
-	if (ret) {
-		printk(KERN_ERR "%s(): ", function);
-		print_fn_descriptor_symbol("%s() returns ", (unsigned long)fn);
-		printk("%d\n", ret);
-	}
-}
-EXPORT_SYMBOL_GPL(__suspend_report_result);
diff --git a/drivers/base/sys.c b/drivers/base/sys.c
index 18febe2..ac7ff6d 100644
--- a/drivers/base/sys.c
+++ b/drivers/base/sys.c
@@ -139,7 +139,7 @@
 		 kobject_name(&cls->kset.kobj));
 	INIT_LIST_HEAD(&cls->drivers);
 	cls->kset.kobj.parent = &system_subsys.kobj;
-	kset_set_kset_s(cls, system_subsys);
+	cls->kset.kobj.kset = &system_subsys;
 	return kset_register(&cls->kset);
 }
 
@@ -153,25 +153,22 @@
 EXPORT_SYMBOL_GPL(sysdev_class_register);
 EXPORT_SYMBOL_GPL(sysdev_class_unregister);
 
-
-static LIST_HEAD(sysdev_drivers);
 static DEFINE_MUTEX(sysdev_drivers_lock);
 
 /**
  *	sysdev_driver_register - Register auxillary driver
- * 	@cls:	Device class driver belongs to.
+ *	@cls:	Device class driver belongs to.
  *	@drv:	Driver.
  *
- *	If @cls is valid, then @drv is inserted into @cls->drivers to be
+ *	@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 sysdev_drivers, and called for
- *	each device.
  */
 
-int sysdev_driver_register(struct sysdev_class * cls,
-			   struct sysdev_driver * drv)
+int sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv)
 {
+	int err = 0;
+
 	mutex_lock(&sysdev_drivers_lock);
 	if (cls && kset_get(&cls->kset)) {
 		list_add_tail(&drv->entry, &cls->drivers);
@@ -182,10 +179,13 @@
 			list_for_each_entry(dev, &cls->kset.list, kobj.entry)
 				drv->add(dev);
 		}
-	} else
-		list_add_tail(&drv->entry, &sysdev_drivers);
+	} else {
+		err = -EINVAL;
+		printk(KERN_ERR "%s: invalid device class\n", __FUNCTION__);
+		WARN_ON(1);
+	}
 	mutex_unlock(&sysdev_drivers_lock);
-	return 0;
+	return err;
 }
 
 
@@ -251,12 +251,6 @@
 		 * code that should have called us.
 		 */
 
-		/* Notify global drivers */
-		list_for_each_entry(drv, &sysdev_drivers, entry) {
-			if (drv->add)
-				drv->add(sysdev);
-		}
-
 		/* Notify class auxillary drivers */
 		list_for_each_entry(drv, &cls->drivers, entry) {
 			if (drv->add)
@@ -272,11 +266,6 @@
 	struct sysdev_driver * drv;
 
 	mutex_lock(&sysdev_drivers_lock);
-	list_for_each_entry(drv, &sysdev_drivers, entry) {
-		if (drv->remove)
-			drv->remove(sysdev);
-	}
-
 	list_for_each_entry(drv, &sysdev->cls->drivers, entry) {
 		if (drv->remove)
 			drv->remove(sysdev);
@@ -293,7 +282,7 @@
  *
  *	Loop over each class of system devices, and the devices in each
  *	of those classes. For each device, we call the shutdown method for
- *	each driver registered for the device - the globals, the auxillaries,
+ *	each driver registered for the device - the auxillaries,
  *	and the class driver.
  *
  *	Note: The list is iterated in reverse order, so that we shut down
@@ -320,13 +309,7 @@
 			struct sysdev_driver * drv;
 			pr_debug(" %s\n", kobject_name(&sysdev->kobj));
 
-			/* Call global drivers first. */
-			list_for_each_entry(drv, &sysdev_drivers, entry) {
-				if (drv->shutdown)
-					drv->shutdown(sysdev);
-			}
-
-			/* Call auxillary drivers next. */
+			/* Call auxillary drivers first */
 			list_for_each_entry(drv, &cls->drivers, entry) {
 				if (drv->shutdown)
 					drv->shutdown(sysdev);
@@ -354,12 +337,6 @@
 		if (drv->resume)
 			drv->resume(dev);
 	}
-
-	/* Call global drivers. */
-	list_for_each_entry(drv, &sysdev_drivers, entry) {
-		if (drv->resume)
-			drv->resume(dev);
-	}
 }
 
 /**
@@ -393,16 +370,7 @@
 		list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) {
 			pr_debug(" %s\n", kobject_name(&sysdev->kobj));
 
-			/* Call global drivers first. */
-			list_for_each_entry(drv, &sysdev_drivers, entry) {
-				if (drv->suspend) {
-					ret = drv->suspend(sysdev, state);
-					if (ret)
-						goto gbl_driver;
-				}
-			}
-
-			/* Call auxillary drivers next. */
+			/* Call auxillary drivers first */
 			list_for_each_entry(drv, &cls->drivers, entry) {
 				if (drv->suspend) {
 					ret = drv->suspend(sysdev, state);
@@ -436,18 +404,7 @@
 		if (err_drv->resume)
 			err_drv->resume(sysdev);
 	}
-	drv = NULL;
 
-gbl_driver:
-	if (drv)
-		printk(KERN_ERR "sysdev driver suspend failed for %s\n",
-				kobject_name(&sysdev->kobj));
-	list_for_each_entry(err_drv, &sysdev_drivers, entry) {
-		if (err_drv == drv)
-			break;
-		if (err_drv->resume)
-			err_drv->resume(sysdev);
-	}
 	/* resume other sysdevs in current class */
 	list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) {
 		if (err_dev == sysdev)
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 4245b7f..ca4d7f0 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -361,8 +361,7 @@
 	default "4096"
 	help
 	  The default value is 4096 kilobytes. Only change this if you know
-	  what are you doing. If you are using IBM S/390, then set this to
-	  8192.
+	  what are you doing.
 
 config BLK_DEV_RAM_BLOCKSIZE
 	int "Default RAM disk block size (bytes)"
diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c
index 9b8278e..acbfe1c 100644
--- a/drivers/char/dsp56k.c
+++ b/drivers/char/dsp56k.c
@@ -513,7 +513,7 @@
 		err = PTR_ERR(dsp56k_class);
 		goto out_chrdev;
 	}
-	class_device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), NULL, "dsp56k");
+	device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), "dsp56k");
 
 	printk(banner);
 	goto out;
@@ -527,7 +527,7 @@
 
 static void __exit dsp56k_cleanup_driver(void)
 {
-	class_device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0));
+	device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0));
 	class_destroy(dsp56k_class);
 	unregister_chrdev(DSP56K_MAJOR, "dsp56k");
 }
diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c
index 8d74b8745e..bd94d5f 100644
--- a/drivers/char/ip2/ip2main.c
+++ b/drivers/char/ip2/ip2main.c
@@ -411,8 +411,8 @@
 			iiResetDelay( i2BoardPtrTable[i] );
 			/* free io addresses and Tibet */
 			release_region( ip2config.addr[i], 8 );
-			class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i));
-			class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1));
+			device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i));
+			device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1));
 		}
 		/* Disable and remove interrupt handler. */
 		if ( (ip2config.irq[i] > 0) && have_requested_irq(ip2config.irq[i]) ) {	
@@ -718,12 +718,12 @@
 			}
 
 			if ( NULL != ( pB = i2BoardPtrTable[i] ) ) {
-				class_device_create(ip2_class, NULL,
+				device_create(ip2_class, NULL,
 						MKDEV(IP2_IPL_MAJOR, 4 * i),
-						NULL, "ipl%d", i);
-				class_device_create(ip2_class, NULL,
+						"ipl%d", i);
+				device_create(ip2_class, NULL,
 						MKDEV(IP2_IPL_MAJOR, 4 * i + 1),
-						NULL, "stat%d", i);
+						"stat%d", i);
 
 			    for ( box = 0; box < ABS_MAX_BOXES; ++box )
 			    {
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
index c2aa44e..0246a2b8 100644
--- a/drivers/char/ipmi/ipmi_devintf.c
+++ b/drivers/char/ipmi/ipmi_devintf.c
@@ -865,7 +865,7 @@
 	entry->dev = dev;
 
 	mutex_lock(&reg_list_mutex);
-	class_device_create(ipmi_class, NULL, dev, device, "ipmi%d", if_num);
+	device_create(ipmi_class, device, dev, "ipmi%d", if_num);
 	list_add(&entry->link, &reg_list);
 	mutex_unlock(&reg_list_mutex);
 }
@@ -883,7 +883,7 @@
 			break;
 		}
 	}
-	class_device_destroy(ipmi_class, dev);
+	device_destroy(ipmi_class, dev);
 	mutex_unlock(&reg_list_mutex);
 }
 
@@ -938,7 +938,7 @@
 	mutex_lock(&reg_list_mutex);
 	list_for_each_entry_safe(entry, entry2, &reg_list, link) {
 		list_del(&entry->link);
-		class_device_destroy(ipmi_class, entry->dev);
+		device_destroy(ipmi_class, entry->dev);
 		kfree(entry);
 	}
 	mutex_unlock(&reg_list_mutex);
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index 3c66f40..1f27be1 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -4624,9 +4624,8 @@
 
 	istallion_class = class_create(THIS_MODULE, "staliomem");
 	for (i = 0; i < 4; i++)
-		class_device_create(istallion_class, NULL,
-				MKDEV(STL_SIOMEMMAJOR, i),
-				NULL, "staliomem%d", i);
+		device_create(istallion_class, NULL, MKDEV(STL_SIOMEMMAJOR, i),
+			      "staliomem%d", i);
 
 	return 0;
 err_deinit:
@@ -4659,8 +4658,7 @@
 	unregister_chrdev(STL_SIOMEMMAJOR, "staliomem");
 
 	for (j = 0; j < 4; j++)
-		class_device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR,
-					j));
+		device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR, j));
 	class_destroy(istallion_class);
 
 	pci_unregister_driver(&stli_pcidriver);
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index 62051f8..c59e2a0 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -799,8 +799,7 @@
 	if (reset)
 		lp_reset(nr);
 
-	class_device_create(lp_class, NULL, MKDEV(LP_MAJOR, nr), port->dev,
-				"lp%d", nr);
+	device_create(lp_class, port->dev, MKDEV(LP_MAJOR, nr), "lp%d", nr);
 
 	printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name, 
 	       (port->irq == PARPORT_IRQ_NONE)?"polling":"interrupt-driven");
@@ -971,7 +970,7 @@
 		if (lp_table[offset].dev == NULL)
 			continue;
 		parport_unregister_device(lp_table[offset].dev);
-		class_device_destroy(lp_class, MKDEV(LP_MAJOR, offset));
+		device_destroy(lp_class, MKDEV(LP_MAJOR, offset));
 	}
 	class_destroy(lp_class);
 }
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c
index 4177f6d..cc5d777 100644
--- a/drivers/char/pcmcia/cm4000_cs.c
+++ b/drivers/char/pcmcia/cm4000_cs.c
@@ -1863,8 +1863,7 @@
 		return ret;
 	}
 
-	class_device_create(cmm_class, NULL, MKDEV(major, i), NULL,
-			    "cmm%d", i);
+	device_create(cmm_class, NULL, MKDEV(major, i), "cmm%d", i);
 
 	return 0;
 }
@@ -1888,7 +1887,7 @@
 	dev_table[devno] = NULL;
 	kfree(dev);
 
-	class_device_destroy(cmm_class, MKDEV(major, devno));
+	device_destroy(cmm_class, MKDEV(major, devno));
 
 	return;
 }
diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c
index b24a3e7..a0b9c87 100644
--- a/drivers/char/pcmcia/cm4040_cs.c
+++ b/drivers/char/pcmcia/cm4040_cs.c
@@ -642,8 +642,7 @@
 		return ret;
 	}
 
-	class_device_create(cmx_class, NULL, MKDEV(major, i), NULL,
-			    "cmx%d", i);
+	device_create(cmx_class, NULL, MKDEV(major, i), "cmx%d", i);
 
 	return 0;
 }
@@ -666,7 +665,7 @@
 	dev_table[devno] = NULL;
 	kfree(dev);
 
-	class_device_destroy(cmx_class, MKDEV(major, devno));
+	device_destroy(cmx_class, MKDEV(major, devno));
 
 	return;
 }
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index de14aea..73de771 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -248,14 +248,19 @@
 	return -ENOIOCTLCMD;
 }
 
+static int legacy_count = CONFIG_LEGACY_PTY_COUNT;
+module_param(legacy_count, int, 0);
+
 static void __init legacy_pty_init(void)
 {
+	if (legacy_count <= 0)
+		return;
 
-	pty_driver = alloc_tty_driver(NR_PTYS);
+	pty_driver = alloc_tty_driver(legacy_count);
 	if (!pty_driver)
 		panic("Couldn't allocate pty driver");
 
-	pty_slave_driver = alloc_tty_driver(NR_PTYS);
+	pty_slave_driver = alloc_tty_driver(legacy_count);
 	if (!pty_slave_driver)
 		panic("Couldn't allocate pty slave driver");
 
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
index 1f0d7c6..bbfa0e2 100644
--- a/drivers/char/raw.c
+++ b/drivers/char/raw.c
@@ -255,10 +255,7 @@
 	.owner	=	THIS_MODULE,
 };
 
-static struct cdev raw_cdev = {
-	.kobj	=	{.name = "raw", },
-	.owner	=	THIS_MODULE,
-};
+static struct cdev raw_cdev;
 
 static int __init raw_init(void)
 {
diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c
index 52753e7..b9c1dba 100644
--- a/drivers/char/snsc.c
+++ b/drivers/char/snsc.c
@@ -441,8 +441,7 @@
 				continue;
 			}
 
-			class_device_create(snsc_class, NULL, dev, NULL,
-						"%s", devname);
+			device_create(snsc_class, NULL, dev, "%s", devname);
 
 			ia64_sn_irtr_intr_enable(scd->scd_nasid,
 						 0 /*ignored */ ,
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index 4a80b2f..45758d5 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -4778,9 +4778,8 @@
 	if (IS_ERR(stallion_class))
 		printk("STALLION: failed to create class\n");
 	for (i = 0; i < 4; i++)
-		class_device_create(stallion_class, NULL,
-				    MKDEV(STL_SIOMEMMAJOR, i), NULL,
-				    "staliomem%d", i);
+		device_create(stallion_class, NULL, MKDEV(STL_SIOMEMMAJOR, i),
+			      "staliomem%d", i);
 
 	return 0;
 err_unrtty:
@@ -4816,7 +4815,7 @@
 	}
 
 	for (i = 0; i < 4; i++)
-		class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i));
+		device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i));
 	unregister_chrdev(STL_SIOMEMMAJOR, "staliomem");
 	class_destroy(stallion_class);
 
diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c
index 35b40b9..cef55c4 100644
--- a/drivers/char/tipar.c
+++ b/drivers/char/tipar.c
@@ -441,8 +441,8 @@
 		goto out;
 	}
 
-	class_device_create(tipar_class, NULL, MKDEV(TIPAR_MAJOR,
-			TIPAR_MINOR + nr), port->dev, "par%d", nr);
+	device_create(tipar_class, port->dev, MKDEV(TIPAR_MAJOR,
+			TIPAR_MINOR + nr), "par%d", nr);
 
 	/* Display informations */
 	pr_info("tipar%d: using %s (%s)\n", nr, port->name, (port->irq ==
@@ -534,7 +534,7 @@
 		if (table[i].dev == NULL)
 			continue;
 		parport_unregister_device(table[i].dev);
-		class_device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, i));
+		device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, i));
 	}
 	class_destroy(tipar_class);
 
diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c
index f1d60f0..db7a731 100644
--- a/drivers/char/viotape.c
+++ b/drivers/char/viotape.c
@@ -871,10 +871,10 @@
 	state[i].cur_part = 0;
 	for (j = 0; j < MAX_PARTITIONS; ++j)
 		state[i].part_stat_rwi[j] = VIOT_IDLE;
-	class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i), NULL,
+	device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i),
 			"iseries!vt%d", i);
-	class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80),
-			NULL, "iseries!nvt%d", i);
+	device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80),
+			"iseries!nvt%d", i);
 	printk(VIOTAPE_KERN_INFO "tape iseries/vt%d is iSeries "
 			"resource %10.10s type %4.4s, model %3.3s\n",
 			i, viotape_unitinfo[i].rsrcname,
@@ -886,8 +886,8 @@
 {
 	int i = vdev->unit_address;
 
-	class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80));
-	class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i));
+	device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80));
+	device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i));
 	return 0;
 }
 
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index 993fa7b..721f86f 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -56,10 +56,6 @@
 
 	  If in doubt, say N.
 
-# 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"
 	default CPU_FREQ_DEFAULT_GOV_USERSPACE if CPU_FREQ_SA1100 || CPU_FREQ_SA1110
@@ -85,6 +81,29 @@
 	  program shall be able to set the CPU dynamically without having
 	  to enable the userspace governor manually.
 
+config CPU_FREQ_DEFAULT_GOV_ONDEMAND
+	bool "ondemand"
+	select CPU_FREQ_GOV_ONDEMAND
+	select CPU_FREQ_GOV_PERFORMANCE
+	help
+	  Use the CPUFreq governor 'ondemand' as default. This allows
+	  you to get a full dynamic frequency capable system by simply
+	  loading your cpufreq low-level hardware driver.
+	  Be aware that not all cpufreq drivers support the ondemand
+	  governor. If unsure have a look at the help section of the
+	  driver. Fallback governor will be the performance governor.
+
+config CPU_FREQ_DEFAULT_GOV_CONSERVATIVE
+	bool "conservative"
+	select CPU_FREQ_GOV_CONSERVATIVE
+	select CPU_FREQ_GOV_PERFORMANCE
+	help
+	  Use the CPUFreq governor 'conservative' as default. This allows
+	  you to get a full dynamic frequency capable system by simply
+	  loading your cpufreq low-level hardware driver.
+	  Be aware that not all cpufreq drivers support the conservative
+	  governor. If unsure have a look at the help section of the
+	  driver. Fallback governor will be the performance governor.
 endchoice
 
 config CPU_FREQ_GOV_PERFORMANCE
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 2f6a73c..5e626b1 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -763,6 +763,8 @@
 	init_completion(&policy->kobj_unregister);
 	INIT_WORK(&policy->update, handle_update);
 
+	/* Set governor before ->init, so that driver could check it */
+	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 	/* call driver. From then on the cpufreq must be able
 	 * to accept all calls to ->verify and ->setpolicy for this CPU
 	 */
@@ -828,7 +830,7 @@
 	/* prepare interface data */
 	policy->kobj.parent = &sys_dev->kobj;
 	policy->kobj.ktype = &ktype_cpufreq;
-	strlcpy(policy->kobj.name, "cpufreq", KOBJ_NAME_LEN);
+	kobject_set_name(&policy->kobj, "cpufreq");
 
 	ret = kobject_register(&policy->kobj);
 	if (ret) {
@@ -1109,12 +1111,7 @@
 	unsigned int ret_freq = 0;
 
 	if (policy) {
-		if (unlikely(lock_policy_rwsem_read(cpu)))
-			return ret_freq;
-
 		ret_freq = policy->cur;
-
-		unlock_policy_rwsem_read(cpu);
 		cpufreq_cpu_put(policy);
 	}
 
@@ -1483,6 +1480,31 @@
 {
 	int ret;
 
+	/* Only must be defined when default governor is known to have latency
+	   restrictions, like e.g. conservative or ondemand.
+	   That this is the case is already ensured in Kconfig
+	*/
+#ifdef CONFIG_CPU_FREQ_GOV_PERFORMANCE
+	struct cpufreq_governor *gov = &cpufreq_gov_performance;
+#else
+	struct cpufreq_governor *gov = NULL;
+#endif
+
+	if (policy->governor->max_transition_latency &&
+	    policy->cpuinfo.transition_latency >
+	    policy->governor->max_transition_latency) {
+		if (!gov)
+			return -EINVAL;
+		else {
+			printk(KERN_WARNING "%s governor failed, too long"
+			       " transition latency of HW, fallback"
+			       " to %s governor\n",
+			       policy->governor->name,
+			       gov->name);
+			policy->governor = gov;
+		}
+	}
+
 	if (!try_module_get(policy->governor->owner))
 		return -EINVAL;
 
@@ -1703,7 +1725,7 @@
 }
 EXPORT_SYMBOL(cpufreq_update_policy);
 
-static int cpufreq_cpu_callback(struct notifier_block *nfb,
+static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb,
 					unsigned long action, void *hcpu)
 {
 	unsigned int cpu = (unsigned long)hcpu;
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index 26f440c..4bd33ce 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -58,7 +58,7 @@
 #define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER	(1000)
 #define DEF_SAMPLING_DOWN_FACTOR		(1)
 #define MAX_SAMPLING_DOWN_FACTOR		(10)
-#define TRANSITION_LATENCY_LIMIT		(10 * 1000)
+#define TRANSITION_LATENCY_LIMIT		(10 * 1000 * 1000)
 
 static void do_dbs_timer(struct work_struct *work);
 
@@ -466,9 +466,6 @@
 		    (!policy->cur))
 			return -EINVAL;
 
-		if (policy->cpuinfo.transition_latency >
-				(TRANSITION_LATENCY_LIMIT * 1000))
-			return -EINVAL;
 		if (this_dbs_info->enable) /* Already enabled */
 			break;
 		 
@@ -551,15 +548,17 @@
 	return 0;
 }
 
-static struct cpufreq_governor cpufreq_gov_dbs = {
-	.name		= "conservative",
-	.governor	= cpufreq_governor_dbs,
-	.owner		= THIS_MODULE,
+struct cpufreq_governor cpufreq_gov_conservative = {
+	.name			= "conservative",
+	.governor		= cpufreq_governor_dbs,
+	.max_transition_latency	= TRANSITION_LATENCY_LIMIT,
+	.owner			= THIS_MODULE,
 };
+EXPORT_SYMBOL(cpufreq_gov_conservative);
 
 static int __init cpufreq_gov_dbs_init(void)
 {
-	return cpufreq_register_governor(&cpufreq_gov_dbs);
+	return cpufreq_register_governor(&cpufreq_gov_conservative);
 }
 
 static void __exit cpufreq_gov_dbs_exit(void)
@@ -567,7 +566,7 @@
 	/* Make sure that the scheduled work is indeed not running */
 	flush_scheduled_work();
 
-	cpufreq_unregister_governor(&cpufreq_gov_dbs);
+	cpufreq_unregister_governor(&cpufreq_gov_conservative);
 }
 
 
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index e794527..369f445 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -47,7 +47,7 @@
 			(def_sampling_rate / MIN_SAMPLING_RATE_RATIO)
 #define MAX_SAMPLING_RATE			(500 * def_sampling_rate)
 #define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER	(1000)
-#define TRANSITION_LATENCY_LIMIT		(10 * 1000)
+#define TRANSITION_LATENCY_LIMIT		(10 * 1000 * 1000)
 
 static void do_dbs_timer(struct work_struct *work);
 
@@ -508,12 +508,6 @@
 		if ((!cpu_online(cpu)) || (!policy->cur))
 			return -EINVAL;
 
-		if (policy->cpuinfo.transition_latency >
-				(TRANSITION_LATENCY_LIMIT * 1000)) {
-			printk(KERN_WARNING "ondemand governor failed to load "
-			       "due to too long transition latency\n");
-			return -EINVAL;
-		}
 		if (this_dbs_info->enable) /* Already enabled */
 			break;
 
@@ -585,11 +579,13 @@
 	return 0;
 }
 
-static struct cpufreq_governor cpufreq_gov_dbs = {
-	.name = "ondemand",
-	.governor = cpufreq_governor_dbs,
-	.owner = THIS_MODULE,
+struct cpufreq_governor cpufreq_gov_ondemand = {
+	.name			= "ondemand",
+	.governor		= cpufreq_governor_dbs,
+	.max_transition_latency = TRANSITION_LATENCY_LIMIT,
+	.owner			= THIS_MODULE,
 };
+EXPORT_SYMBOL(cpufreq_gov_ondemand);
 
 static int __init cpufreq_gov_dbs_init(void)
 {
@@ -598,12 +594,12 @@
 		printk(KERN_ERR "Creation of kondemand failed\n");
 		return -EFAULT;
 	}
-	return cpufreq_register_governor(&cpufreq_gov_dbs);
+	return cpufreq_register_governor(&cpufreq_gov_ondemand);
 }
 
 static void __exit cpufreq_gov_dbs_exit(void)
 {
-	cpufreq_unregister_governor(&cpufreq_gov_dbs);
+	cpufreq_unregister_governor(&cpufreq_gov_ondemand);
 	destroy_workqueue(kondemand_wq);
 }
 
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index 917b9ba..8a45d0f 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -164,8 +164,7 @@
 	return -1;
 }
 
-static void
-cpufreq_stats_free_table (unsigned int cpu)
+static void __cpuexit cpufreq_stats_free_table(unsigned int cpu)
 {
 	struct cpufreq_stats *stat = cpufreq_stats_table[cpu];
 	struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
@@ -305,8 +304,9 @@
 	return 0;
 }
 
-static int cpufreq_stat_cpu_callback(struct notifier_block *nfb,
-					unsigned long action, void *hcpu)
+static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb,
+					       unsigned long action,
+					       void *hcpu)
 {
 	unsigned int cpu = (unsigned long)hcpu;
 
@@ -323,7 +323,7 @@
 	return NOTIFY_OK;
 }
 
-static struct notifier_block cpufreq_stat_cpu_notifier =
+static struct notifier_block cpufreq_stat_cpu_notifier __cpuinitdata =
 {
 	.notifier_call = cpufreq_stat_cpu_callback,
 };
@@ -356,8 +356,7 @@
 
 	register_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
 	for_each_online_cpu(cpu) {
-		cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier,
-				CPU_ONLINE, (void *)(long)cpu);
+		cpufreq_update_policy(cpu);
 	}
 	return 0;
 }
@@ -372,13 +371,12 @@
 			CPUFREQ_TRANSITION_NOTIFIER);
 	unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
 	for_each_online_cpu(cpu) {
-		cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier,
-						CPU_DEAD, (void *)(long)cpu);
+		cpufreq_stats_free_table(cpu);
 	}
 }
 
 MODULE_AUTHOR ("Zou Nan hai <nanhai.zou@intel.com>");
-MODULE_DESCRIPTION ("'cpufreq_stats' - A driver to export cpufreq stats"
+MODULE_DESCRIPTION ("'cpufreq_stats' - A driver to export cpufreq stats "
 				"through sysfs filesystem");
 MODULE_LICENSE ("GPL");
 
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index 4a0576b..3706b2b 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -743,7 +743,7 @@
  *	/sys/devices/system/edac/mc
  */
 static struct kset mc_kset = {
-	.kobj = {.name = "mc", .ktype = &ktype_mc_set_attribs },
+	.kobj = {.ktype = &ktype_mc_set_attribs },
 	.ktype = &ktype_mci,
 };
 
@@ -1010,6 +1010,7 @@
 	}
 
 	/* Init the MC's kobject */
+	kobject_set_name(&mc_kset.kobj, "mc");
 	mc_kset.kobj.parent = &edac_class->kset.kobj;
 
 	/* register the mc_kset */
diff --git a/drivers/eisa/eisa-bus.c b/drivers/eisa/eisa-bus.c
index d944647..4d4a473 100644
--- a/drivers/eisa/eisa-bus.c
+++ b/drivers/eisa/eisa-bus.c
@@ -128,16 +128,11 @@
 	return 0;
 }
 
-static int eisa_bus_uevent(struct device *dev, char **envp, int num_envp,
-			   char *buffer, int buffer_size)
+static int eisa_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct eisa_device *edev = to_eisa_device(dev);
-	int i = 0;
-	int length = 0;
 
-	add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
-		       "MODALIAS=" EISA_DEVICE_MODALIAS_FMT, edev->id.sig);
-	envp[i] = NULL;
+	add_uevent_var(env, "MODALIAS=" EISA_DEVICE_MODALIAS_FMT, edev->id.sig);
 	return 0;
 }
 
diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c
index 2b65863..56681b3 100644
--- a/drivers/firewire/fw-device.c
+++ b/drivers/firewire/fw-device.c
@@ -130,23 +130,16 @@
 }
 
 static int
-fw_unit_uevent(struct device *dev, char **envp, int num_envp,
-	       char *buffer, int buffer_size)
+fw_unit_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct fw_unit *unit = fw_unit(dev);
 	char modalias[64];
-	int length = 0;
-	int i = 0;
 
 	get_modalias(unit, modalias, sizeof(modalias));
 
-	if (add_uevent_var(envp, num_envp, &i,
-			   buffer, buffer_size, &length,
-			   "MODALIAS=%s", modalias))
+	if (add_uevent_var(env, "MODALIAS=%s", modalias))
 		return -ENOMEM;
 
-	envp[i] = NULL;
-
 	return 0;
 }
 
diff --git a/drivers/firmware/dmi-id.c b/drivers/firmware/dmi-id.c
index 59c3b5a..b6e1eb7 100644
--- a/drivers/firmware/dmi-id.c
+++ b/drivers/firmware/dmi-id.c
@@ -13,21 +13,31 @@
 #include <linux/device.h>
 #include <linux/autoconf.h>
 
-#define DEFINE_DMI_ATTR(_name, _mode, _show)		\
-static struct device_attribute sys_dmi_##_name##_attr =	\
-	__ATTR(_name, _mode, _show, NULL);
+struct dmi_device_attribute{
+	struct device_attribute dev_attr;
+	int field;
+};
+#define to_dmi_dev_attr(_dev_attr) \
+	container_of(_dev_attr, struct dmi_device_attribute, dev_attr)
 
-#define DEFINE_DMI_ATTR_WITH_SHOW(_name, _mode, _field)			\
-static ssize_t sys_dmi_##_name##_show(struct device *dev,		\
-				      struct device_attribute *attr,	\
-				      char *page)			\
-{									\
-	ssize_t len;							\
-	len = scnprintf(page, PAGE_SIZE, "%s\n", dmi_get_system_info(_field)); \
-	page[len-1] = '\n';						\
-	return len;							\
-}									\
-DEFINE_DMI_ATTR(_name, _mode, sys_dmi_##_name##_show);
+static ssize_t sys_dmi_field_show(struct device *dev,
+				  struct device_attribute *attr,
+				  char *page)
+{
+	int field = to_dmi_dev_attr(attr)->field;
+	ssize_t len;
+	len = scnprintf(page, PAGE_SIZE, "%s\n", dmi_get_system_info(field));
+	page[len-1] = '\n';
+	return len;
+}
+
+#define DMI_ATTR(_name, _mode, _show, _field)			\
+	{ .dev_attr = __ATTR(_name, _mode, _show, NULL),	\
+	  .field = _field }
+
+#define DEFINE_DMI_ATTR_WITH_SHOW(_name, _mode, _field)		\
+static struct dmi_device_attribute sys_dmi_##_name##_attr =	\
+	DMI_ATTR(_name, _mode, sys_dmi_field_show, _field);
 
 DEFINE_DMI_ATTR_WITH_SHOW(bios_vendor,		0444, DMI_BIOS_VENDOR);
 DEFINE_DMI_ATTR_WITH_SHOW(bios_version,		0444, DMI_BIOS_VERSION);
@@ -121,7 +131,8 @@
 	return r+1;
 }
 
-DEFINE_DMI_ATTR(modalias, 0444, sys_dmi_modalias_show);
+static struct device_attribute sys_dmi_modalias_attr =
+	__ATTR(modalias, 0444, sys_dmi_modalias_show, NULL);
 
 static struct attribute *sys_dmi_attributes[DMI_STRING_MAX+2];
 
@@ -134,14 +145,17 @@
 	NULL
 };
 
-static int dmi_dev_uevent(struct device *dev, char **envp,
-			    int num_envp, char *buffer, int buffer_size)
+static int dmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
-	strcpy(buffer, "MODALIAS=");
-	get_modalias(buffer+9, buffer_size-9);
-	envp[0] = buffer;
-	envp[1] = NULL;
+	ssize_t len;
 
+	if (add_uevent_var(env, "MODALIAS="))
+		return -ENOMEM;
+	len = get_modalias(&env->buf[env->buflen - 1],
+			   sizeof(env->buf) - env->buflen);
+	if (len >= (sizeof(env->buf) - env->buflen))
+		return -ENOMEM;
+	env->buflen += len;
 	return 0;
 }
 
@@ -157,7 +171,7 @@
 
 #define ADD_DMI_ATTR(_name, _field) \
 	if (dmi_get_system_info(_field)) \
-		sys_dmi_attributes[i++] = & sys_dmi_##_name##_attr.attr;
+		sys_dmi_attributes[i++] = &sys_dmi_##_name##_attr.dev_attr.attr;
 
 extern int dmi_available;
 
diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c
index 0fb730e..6942e06 100644
--- a/drivers/firmware/edd.c
+++ b/drivers/firmware/edd.c
@@ -625,13 +625,13 @@
 	kfree(dev);
 }
 
-static struct kobj_type ktype_edd = {
+static struct kobj_type edd_ktype = {
 	.release	= edd_release,
 	.sysfs_ops	= &edd_attr_ops,
 	.default_attrs	= def_attrs,
 };
 
-static decl_subsys(edd,&ktype_edd,NULL);
+static decl_subsys(edd, &edd_ktype, NULL);
 
 
 /**
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
index bfd2d67..858a7b9 100644
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -402,7 +402,7 @@
 	NULL,
 };
 
-static struct kobj_type ktype_efivar = {
+static struct kobj_type efivar_ktype = {
 	.release = efivar_release,
 	.sysfs_ops = &efivar_attr_ops,
 	.default_attrs = def_attrs,
@@ -583,7 +583,7 @@
 	NULL,	/* maybe more in the future? */
 };
 
-static decl_subsys(vars, &ktype_efivar, NULL);
+static decl_subsys(vars, &efivar_ktype, NULL);
 static decl_subsys(efi, NULL, NULL);
 
 /*
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index d663e69..910a62d 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -67,20 +67,16 @@
 #ifdef	CONFIG_HOTPLUG
 
 /* uevent helps with hotplug: modprobe -q $(MODALIAS) */
-static int i2c_device_uevent(struct device *dev, char **envp, int num_envp,
-		      char *buffer, int buffer_size)
+static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct i2c_client	*client = to_i2c_client(dev);
-	int			i = 0, length = 0;
 
 	/* by definition, legacy drivers can't hotplug */
 	if (dev->driver || !client->driver_name)
 		return 0;
 
-	if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
-			"MODALIAS=%s", client->driver_name))
+	if (add_uevent_var(env, "MODALIAS=%s", client->driver_name))
 		return -ENOMEM;
-	envp[i] = NULL;
 	dev_dbg(dev, "uevent\n");
 	return 0;
 }
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index e96212c..a96a8b1 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -1663,20 +1663,13 @@
 	__ATTR_NULL
 };
 
-static int ide_uevent(struct device *dev, char **envp, int num_envp,
-		      char *buffer, int buffer_size)
+static int ide_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	ide_drive_t *drive = to_ide_device(dev);
-	int i = 0;
-	int length = 0;
 
-	add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
-		       "MEDIA=%s", media_string(drive));
-	add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
-		       "DRIVENAME=%s", drive->name);
-	add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
-		       "MODALIAS=ide:m-%s", media_string(drive));
-	envp[i] = NULL;
+	add_uevent_var(env, "MEDIA=%s", media_string(drive));
+	add_uevent_var(env, "DRIVENAME=%s", drive->name);
+	add_uevent_var(env, "MODALIAS=ide:m-%s", media_string(drive));
 	return 0;
 }
 
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
index 2ffd534..1939fee 100644
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -153,8 +153,7 @@
 };
 
 static int nodemgr_bus_match(struct device * dev, struct device_driver * drv);
-static int nodemgr_uevent(struct device *dev, char **envp, int num_envp,
-			  char *buffer, int buffer_size);
+static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env);
 static void nodemgr_resume_ne(struct node_entry *ne);
 static void nodemgr_remove_ne(struct node_entry *ne);
 static struct node_entry *find_entry_by_guid(u64 guid);
@@ -1160,12 +1159,9 @@
 
 #ifdef CONFIG_HOTPLUG
 
-static int nodemgr_uevent(struct device *dev, char **envp, int num_envp,
-			  char *buffer, int buffer_size)
+static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct unit_directory *ud;
-	int i = 0;
-	int length = 0;
 	int retval = 0;
 	/* ieee1394:venNmoNspNverN */
 	char buf[8 + 1 + 3 + 8 + 2 + 8 + 2 + 8 + 3 + 8 + 1];
@@ -1180,9 +1176,7 @@
 
 #define PUT_ENVP(fmt,val) 					\
 do {								\
-	retval = add_uevent_var(envp, num_envp, &i,		\
-				buffer, buffer_size, &length,	\
-				fmt, val);			\
+	retval = add_uevent_var(env, fmt, val);		\
 	if (retval)						\
 		return retval;					\
 } while (0)
@@ -1201,15 +1195,12 @@
 
 #undef PUT_ENVP
 
-	envp[i] = NULL;
-
 	return 0;
 }
 
 #else
 
-static int nodemgr_uevent(struct device *dev, char **envp, int num_envp,
-			  char *buffer, int buffer_size)
+static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	return -ENODEV;
 }
diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c
index 70b77ae..3d40506 100644
--- a/drivers/infiniband/core/sysfs.c
+++ b/drivers/infiniband/core/sysfs.c
@@ -434,21 +434,18 @@
 	kfree(dev);
 }
 
-static int ib_device_uevent(struct class_device *cdev, char **envp,
-			    int num_envp, char *buf, int size)
+static int ib_device_uevent(struct class_device *cdev,
+			    struct kobj_uevent_env *env)
 {
 	struct ib_device *dev = container_of(cdev, struct ib_device, class_dev);
-	int i = 0, len = 0;
 
-	if (add_uevent_var(envp, num_envp, &i, buf, size, &len,
-			   "NAME=%s", dev->name))
+	if (add_uevent_var(env, "NAME=%s", dev->name))
 		return -ENOMEM;
 
 	/*
 	 * It would be nice to pass the node GUID with the event...
 	 */
 
-	envp[i] = NULL;
 	return 0;
 }
 
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 5fe7555..5dc361c 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -859,87 +859,66 @@
  * Input uevent interface - loading event handlers based on
  * device bitfields.
  */
-static int input_add_uevent_bm_var(char **envp, int num_envp, int *cur_index,
-				   char *buffer, int buffer_size, int *cur_len,
+static int input_add_uevent_bm_var(struct kobj_uevent_env *env,
 				   const char *name, unsigned long *bitmap, int max)
 {
-	if (*cur_index >= num_envp - 1)
+	int len;
+
+	if (add_uevent_var(env, "%s=", name))
 		return -ENOMEM;
 
-	envp[*cur_index] = buffer + *cur_len;
-
-	*cur_len += snprintf(buffer + *cur_len, max(buffer_size - *cur_len, 0), name);
-	if (*cur_len >= buffer_size)
+	len = input_print_bitmap(&env->buf[env->buflen - 1],
+				 sizeof(env->buf) - env->buflen,
+				 bitmap, max, 0);
+	if (len >= (sizeof(env->buf) - env->buflen))
 		return -ENOMEM;
 
-	*cur_len += input_print_bitmap(buffer + *cur_len,
-					max(buffer_size - *cur_len, 0),
-					bitmap, max, 0) + 1;
-	if (*cur_len > buffer_size)
-		return -ENOMEM;
-
-	(*cur_index)++;
+	env->buflen += len;
 	return 0;
 }
 
-static int input_add_uevent_modalias_var(char **envp, int num_envp, int *cur_index,
-					 char *buffer, int buffer_size, int *cur_len,
+static int input_add_uevent_modalias_var(struct kobj_uevent_env *env,
 					 struct input_dev *dev)
 {
-	if (*cur_index >= num_envp - 1)
+	int len;
+
+	if (add_uevent_var(env, "MODALIAS="))
 		return -ENOMEM;
 
-	envp[*cur_index] = buffer + *cur_len;
-
-	*cur_len += snprintf(buffer + *cur_len, max(buffer_size - *cur_len, 0),
-			     "MODALIAS=");
-	if (*cur_len >= buffer_size)
+	len = input_print_modalias(&env->buf[env->buflen - 1],
+				   sizeof(env->buf) - env->buflen,
+				   dev, 0);
+	if (len >= (sizeof(env->buf) - env->buflen))
 		return -ENOMEM;
 
-	*cur_len += input_print_modalias(buffer + *cur_len,
-					 max(buffer_size - *cur_len, 0),
-					 dev, 0) + 1;
-	if (*cur_len > buffer_size)
-		return -ENOMEM;
-
-	(*cur_index)++;
+	env->buflen += len;
 	return 0;
 }
 
 #define INPUT_ADD_HOTPLUG_VAR(fmt, val...)				\
 	do {								\
-		int err = add_uevent_var(envp, num_envp, &i,		\
-					buffer, buffer_size, &len,	\
-					fmt, val);			\
+		int err = add_uevent_var(env, fmt, val);		\
 		if (err)						\
 			return err;					\
 	} while (0)
 
 #define INPUT_ADD_HOTPLUG_BM_VAR(name, bm, max)				\
 	do {								\
-		int err = input_add_uevent_bm_var(envp, num_envp, &i,	\
-					buffer, buffer_size, &len,	\
-					name, bm, max);			\
+		int err = input_add_uevent_bm_var(env, name, bm, max);	\
 		if (err)						\
 			return err;					\
 	} while (0)
 
 #define INPUT_ADD_HOTPLUG_MODALIAS_VAR(dev)				\
 	do {								\
-		int err = input_add_uevent_modalias_var(envp,		\
-					num_envp, &i,			\
-					buffer, buffer_size, &len,	\
-					dev);				\
+		int err = input_add_uevent_modalias_var(env, dev);	\
 		if (err)						\
 			return err;					\
 	} while (0)
 
-static int input_dev_uevent(struct device *device, char **envp,
-			    int num_envp, char *buffer, int buffer_size)
+static int input_dev_uevent(struct device *device, struct kobj_uevent_env *env)
 {
 	struct input_dev *dev = to_input_dev(device);
-	int i = 0;
-	int len = 0;
 
 	INPUT_ADD_HOTPLUG_VAR("PRODUCT=%x/%x/%x/%x",
 				dev->id.bustype, dev->id.vendor,
@@ -971,7 +950,6 @@
 
 	INPUT_ADD_HOTPLUG_MODALIAS_VAR(dev);
 
-	envp[i] = NULL;
 	return 0;
 }
 
diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c
index 906bf5e..c19f77f 100644
--- a/drivers/input/misc/pcspkr.c
+++ b/drivers/input/misc/pcspkr.c
@@ -17,17 +17,18 @@
 #include <linux/init.h>
 #include <linux/input.h>
 #include <linux/platform_device.h>
-#include <asm/8253pit.h>
 #include <asm/io.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 MODULE_DESCRIPTION("PC Speaker beeper driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pcspkr");
 
 #ifdef CONFIG_X86
 /* Use the global PIT lock ! */
 #include <asm/i8253.h>
 #else
+#include <asm/8253pit.h>
 static DEFINE_SPINLOCK(i8253_lock);
 #endif
 
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index 372ca49..b3bc15a 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -876,18 +876,14 @@
 
 #define SERIO_ADD_UEVENT_VAR(fmt, val...)				\
 	do {								\
-		int err = add_uevent_var(envp, num_envp, &i,	\
-					buffer, buffer_size, &len,	\
-					fmt, val);			\
+		int err = add_uevent_var(env, fmt, val);		\
 		if (err)						\
 			return err;					\
 	} while (0)
 
-static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
+static int serio_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct serio *serio;
-	int i = 0;
-	int len = 0;
 
 	if (!dev)
 		return -ENODEV;
@@ -900,7 +896,6 @@
 	SERIO_ADD_UEVENT_VAR("SERIO_EXTRA=%02x", serio->id.extra);
 	SERIO_ADD_UEVENT_VAR("MODALIAS=serio:ty%02Xpr%02Xid%02Xex%02X",
 				serio->id.type, serio->id.proto, serio->id.id, serio->id.extra);
-	envp[i] = NULL;
 
 	return 0;
 }
@@ -908,7 +903,7 @@
 
 #else
 
-static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
+static int serio_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	return -ENODEV;
 }
diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c
index b04a178..f8b7978 100644
--- a/drivers/isdn/hisax/avm_pci.c
+++ b/drivers/isdn/hisax/avm_pci.c
@@ -20,7 +20,6 @@
 #include <linux/isapnp.h>
 #include <linux/interrupt.h>
 
-extern const char *CardType[];
 static const char *avm_pci_rev = "$Revision: 1.29.2.4 $";
 
 #define  AVM_FRITZ_PCI		1
@@ -726,100 +725,15 @@
 	return(0);
 }
 
-#ifdef CONFIG_PCI
-static struct pci_dev *dev_avm __devinitdata = NULL;
-#endif
-#ifdef __ISAPNP__
-static struct pnp_card *pnp_avm_c __devinitdata = NULL;
-#endif
-
-int __devinit
-setup_avm_pcipnp(struct IsdnCard *card)
+static int __devinit avm_setup_rest(struct IsdnCardState *cs)
 {
 	u_int val, ver;
-	struct IsdnCardState *cs = card->cs;
-	char tmp[64];
 
-	strcpy(tmp, avm_pci_rev);
-	printk(KERN_INFO "HiSax: AVM PCI driver Rev. %s\n", HiSax_getrev(tmp));
-	if (cs->typ != ISDN_CTYPE_FRITZPCI)
-		return (0);
-	if (card->para[1]) {
-		/* old manual method */
-		cs->hw.avm.cfg_reg = card->para[1];
-		cs->irq = card->para[0];
-		cs->subtyp = AVM_FRITZ_PNP;
-		goto ready;
-	}
-#ifdef __ISAPNP__
-	if (isapnp_present()) {
-		struct pnp_dev *pnp_avm_d = NULL;
-		if ((pnp_avm_c = pnp_find_card(
-			ISAPNP_VENDOR('A', 'V', 'M'),
-			ISAPNP_FUNCTION(0x0900), pnp_avm_c))) {
-			if ((pnp_avm_d = pnp_find_dev(pnp_avm_c,
-				ISAPNP_VENDOR('A', 'V', 'M'),
-				ISAPNP_FUNCTION(0x0900), pnp_avm_d))) {
-				int err;
-
-				pnp_disable_dev(pnp_avm_d);
-				err = pnp_activate_dev(pnp_avm_d);
-				if (err<0) {
-					printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
-						__FUNCTION__, err);
-					return(0);
-				}
-				cs->hw.avm.cfg_reg =
-					pnp_port_start(pnp_avm_d, 0);
-				cs->irq = pnp_irq(pnp_avm_d, 0);
-				if (!cs->irq) {
-					printk(KERN_ERR "FritzPnP:No IRQ\n");
-					return(0);
-				}
-				if (!cs->hw.avm.cfg_reg) {
-					printk(KERN_ERR "FritzPnP:No IO address\n");
-					return(0);
-				}
-				cs->subtyp = AVM_FRITZ_PNP;
-				goto ready;
-			}
-		}
-	} else {
-		printk(KERN_INFO "FritzPnP: no ISA PnP present\n");
-	}
-#endif
-#ifdef CONFIG_PCI
-	if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM,
-		PCI_DEVICE_ID_AVM_A1,  dev_avm))) {
-		if (pci_enable_device(dev_avm))
-			return(0);
-		cs->irq = dev_avm->irq;
-		if (!cs->irq) {
-			printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n");
-			return(0);
-		}
-		cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1);
-		if (!cs->hw.avm.cfg_reg) {
-			printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n");
-			return(0);
-		}
-		cs->subtyp = AVM_FRITZ_PCI;
-	} else {
-		printk(KERN_WARNING "FritzPCI: No PCI card found\n");
-		return(0);
-	}
-	cs->irq_flags |= IRQF_SHARED;
-#else
-	printk(KERN_WARNING "FritzPCI: NO_PCI_BIOS\n");
-	return (0);
-#endif /* CONFIG_PCI */
-ready:
 	cs->hw.avm.isac = cs->hw.avm.cfg_reg + 0x10;
 	if (!request_region(cs->hw.avm.cfg_reg, 32,
 		(cs->subtyp == AVM_FRITZ_PCI) ? "avm PCI" : "avm PnP")) {
 		printk(KERN_WARNING
-		       "HiSax: %s config port %x-%x already in use\n",
-		       CardType[card->typ],
+		       "HiSax: Fritz!PCI/PNP config port %x-%x already in use\n",
 		       cs->hw.avm.cfg_reg,
 		       cs->hw.avm.cfg_reg + 31);
 		return (0);
@@ -860,3 +774,137 @@
 	ISACVersion(cs, (cs->subtyp == AVM_FRITZ_PCI) ? "AVM PCI:" : "AVM PnP:");
 	return (1);
 }
+
+#ifndef __ISAPNP__
+
+static int __devinit avm_pnp_setup(struct IsdnCardState *cs)
+{
+	return(1);	/* no-op: success */
+}
+
+#else
+
+static struct pnp_card *pnp_avm_c __devinitdata = NULL;
+
+static int __devinit avm_pnp_setup(struct IsdnCardState *cs)
+{
+	struct pnp_dev *pnp_avm_d = NULL;
+
+	if (!isapnp_present())
+		return(1);	/* no-op: success */
+
+	if ((pnp_avm_c = pnp_find_card(
+		ISAPNP_VENDOR('A', 'V', 'M'),
+		ISAPNP_FUNCTION(0x0900), pnp_avm_c))) {
+		if ((pnp_avm_d = pnp_find_dev(pnp_avm_c,
+			ISAPNP_VENDOR('A', 'V', 'M'),
+			ISAPNP_FUNCTION(0x0900), pnp_avm_d))) {
+			int err;
+
+			pnp_disable_dev(pnp_avm_d);
+			err = pnp_activate_dev(pnp_avm_d);
+			if (err<0) {
+				printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+					__FUNCTION__, err);
+				return(0);
+			}
+			cs->hw.avm.cfg_reg =
+				pnp_port_start(pnp_avm_d, 0);
+			cs->irq = pnp_irq(pnp_avm_d, 0);
+			if (!cs->irq) {
+				printk(KERN_ERR "FritzPnP:No IRQ\n");
+				return(0);
+			}
+			if (!cs->hw.avm.cfg_reg) {
+				printk(KERN_ERR "FritzPnP:No IO address\n");
+				return(0);
+			}
+			cs->subtyp = AVM_FRITZ_PNP;
+
+			return (2);	/* goto 'ready' label */
+		}
+	}
+
+	return (1);
+}
+
+#endif /* __ISAPNP__ */
+
+#ifndef CONFIG_PCI
+
+static int __devinit avm_pci_setup(struct IsdnCardState *cs)
+{
+	return(1);	/* no-op: success */
+}
+
+#else
+
+static struct pci_dev *dev_avm __devinitdata = NULL;
+
+static int __devinit avm_pci_setup(struct IsdnCardState *cs)
+{
+	if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM,
+		PCI_DEVICE_ID_AVM_A1, dev_avm))) {
+
+		if (pci_enable_device(dev_avm))
+			return(0);
+
+		cs->irq = dev_avm->irq;
+		if (!cs->irq) {
+			printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n");
+			return(0);
+		}
+
+		cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1);
+		if (!cs->hw.avm.cfg_reg) {
+			printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n");
+			return(0);
+		}
+
+		cs->subtyp = AVM_FRITZ_PCI;
+	} else {
+		printk(KERN_WARNING "FritzPCI: No PCI card found\n");
+		return(0);
+	}
+
+	cs->irq_flags |= IRQF_SHARED;
+
+	return (1);
+}
+
+#endif /* CONFIG_PCI */
+
+int __devinit
+setup_avm_pcipnp(struct IsdnCard *card)
+{
+	struct IsdnCardState *cs = card->cs;
+	char tmp[64];
+	int rc;
+
+	strcpy(tmp, avm_pci_rev);
+	printk(KERN_INFO "HiSax: AVM PCI driver Rev. %s\n", HiSax_getrev(tmp));
+
+	if (cs->typ != ISDN_CTYPE_FRITZPCI)
+		return (0);
+
+	if (card->para[1]) {
+		/* old manual method */
+		cs->hw.avm.cfg_reg = card->para[1];
+		cs->irq = card->para[0];
+		cs->subtyp = AVM_FRITZ_PNP;
+		goto ready;
+	}
+
+	rc = avm_pnp_setup(cs);
+	if (rc < 1)
+		return (0);
+	if (rc == 2)
+		goto ready;
+
+	rc = avm_pci_setup(cs);
+	if (rc < 1)
+		return (0);
+
+ready:
+	return avm_setup_rest(cs);
+}
diff --git a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c
index 6339bb4..99ef3b4 100644
--- a/drivers/isdn/hisax/bkm_a8.c
+++ b/drivers/isdn/hisax/bkm_a8.c
@@ -20,8 +20,6 @@
 #include <linux/pci.h>
 #include "bkm_ax.h"
 
-#ifdef CONFIG_PCI
-
 #define	ATTEMPT_PCI_REMAPPING	/* Required for PLX rev 1 */
 
 extern const char *CardType[];
@@ -279,12 +277,9 @@
 static u_char pci_device_fn __devinitdata = 0;
 static u_char pci_irq __devinitdata = 0;
 
-#endif /* CONFIG_PCI */
-
 int __devinit
 setup_sct_quadro(struct IsdnCard *card)
 {
-#ifdef CONFIG_PCI
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
 	u_int found = 0;
@@ -442,7 +437,4 @@
 		sct_quadro_subtypes[cs->subtyp],
 		readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ID));
 	return (1);
-#else
-	printk(KERN_ERR "HiSax: bkm_a8 only supported on PCI Systems\n");
-#endif /* CONFIG_PCI */
 }
diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c
index 6eebeb4..8267450 100644
--- a/drivers/isdn/hisax/diva.c
+++ b/drivers/isdn/hisax/diva.c
@@ -25,8 +25,6 @@
 #include <linux/pci.h>
 #include <linux/isapnp.h>
 
-extern const char *CardType[];
-
 static const char *Diva_revision = "$Revision: 1.33.2.6 $";
 
 #define byteout(addr,val) outb(val,addr)
@@ -906,225 +904,15 @@
 	return(0);
 }
 
-static struct pci_dev *dev_diva __devinitdata = NULL;
-static struct pci_dev *dev_diva_u __devinitdata = NULL;
-static struct pci_dev *dev_diva201 __devinitdata = NULL;
-static struct pci_dev *dev_diva202 __devinitdata = NULL;
-
-#ifdef __ISAPNP__
-static struct isapnp_device_id diva_ids[] __devinitdata = {
-	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
-	  ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), 
-	  (unsigned long) "Diva picola" },
-	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
-	  ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x51), 
-	  (unsigned long) "Diva picola" },
-	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
-	  ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), 
-	  (unsigned long) "Diva 2.0" },
-	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
-	  ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x71), 
-	  (unsigned long) "Diva 2.0" },
-	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
-	  ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), 
-	  (unsigned long) "Diva 2.01" },
-	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
-	  ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0xA1), 
-	  (unsigned long) "Diva 2.01" },
-	{ 0, }
-};
-
-static struct isapnp_device_id *ipid __devinitdata = &diva_ids[0];
-static struct pnp_card *pnp_c __devinitdata = NULL;
-#endif
-
-
-int __devinit
-setup_diva(struct IsdnCard *card)
+static int __devinit setup_diva_common(struct IsdnCardState *cs)
 {
-	int bytecnt = 8;
+	int bytecnt;
 	u_char val;
-	struct IsdnCardState *cs = card->cs;
-	char tmp[64];
 
-	strcpy(tmp, Diva_revision);
-	printk(KERN_INFO "HiSax: Eicon.Diehl Diva driver Rev. %s\n", HiSax_getrev(tmp));
-	if (cs->typ != ISDN_CTYPE_DIEHLDIVA)
-		return(0);
-	cs->hw.diva.status = 0;
-	if (card->para[1]) {
-		cs->hw.diva.ctrl_reg = 0;
-		cs->hw.diva.cfg_reg = card->para[1];
-		val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR,
-			cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID);
-		printk(KERN_INFO "Diva: IPAC version %x\n", val);
-		if ((val == 1) || (val==2)) {
-			cs->subtyp = DIVA_IPAC_ISA;
-			cs->hw.diva.ctrl = 0;
-			cs->hw.diva.isac = card->para[1] + DIVA_IPAC_DATA;
-			cs->hw.diva.hscx = card->para[1] + DIVA_IPAC_DATA;
-			cs->hw.diva.isac_adr = card->para[1] + DIVA_IPAC_ADR;
-			cs->hw.diva.hscx_adr = card->para[1] + DIVA_IPAC_ADR;
-			test_and_set_bit(HW_IPAC, &cs->HW_Flags);
-		} else {
-			cs->subtyp = DIVA_ISA;
-			cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL;
-			cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA;
-			cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA;
-			cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR;
-			cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR;
-		}
-		cs->irq = card->para[0];
-	} else {
-#ifdef __ISAPNP__
-		if (isapnp_present()) {
-			struct pnp_dev *pnp_d;
-			while(ipid->card_vendor) {
-				if ((pnp_c = pnp_find_card(ipid->card_vendor,
-					ipid->card_device, pnp_c))) {
-					pnp_d = NULL;
-					if ((pnp_d = pnp_find_dev(pnp_c,
-						ipid->vendor, ipid->function, pnp_d))) {
-						int err;
-
-						printk(KERN_INFO "HiSax: %s detected\n",
-							(char *)ipid->driver_data);
-						pnp_disable_dev(pnp_d);
-						err = pnp_activate_dev(pnp_d);
-						if (err<0) {
-							printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
-								__FUNCTION__, err);
-							return(0);
-						}
-						card->para[1] = pnp_port_start(pnp_d, 0);
-						card->para[0] = pnp_irq(pnp_d, 0);
-						if (!card->para[0] || !card->para[1]) {
-							printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n",
-								card->para[0], card->para[1]);
-							pnp_disable_dev(pnp_d); 
-							return(0);
-						}
-						cs->hw.diva.cfg_reg  = card->para[1];
-						cs->irq = card->para[0];
-						if (ipid->function == ISAPNP_FUNCTION(0xA1)) {
-							cs->subtyp = DIVA_IPAC_ISA;
-							cs->hw.diva.ctrl = 0;
-							cs->hw.diva.isac =
-								card->para[1] + DIVA_IPAC_DATA;
-							cs->hw.diva.hscx =
-								card->para[1] + DIVA_IPAC_DATA;
-							cs->hw.diva.isac_adr =
-								card->para[1] + DIVA_IPAC_ADR;
-							cs->hw.diva.hscx_adr =
-								card->para[1] + DIVA_IPAC_ADR;
-							test_and_set_bit(HW_IPAC, &cs->HW_Flags);
-						} else {
-							cs->subtyp = DIVA_ISA;
-							cs->hw.diva.ctrl =
-								card->para[1] + DIVA_ISA_CTRL;
-							cs->hw.diva.isac =
-								card->para[1] + DIVA_ISA_ISAC_DATA;
-							cs->hw.diva.hscx =
-								card->para[1] + DIVA_HSCX_DATA;
-							cs->hw.diva.isac_adr =
-								card->para[1] + DIVA_ISA_ISAC_ADR;
-							cs->hw.diva.hscx_adr =
-								card->para[1] + DIVA_HSCX_ADR;
-						}
-						goto ready;
-					} else {
-						printk(KERN_ERR "Diva PnP: PnP error card found, no device\n");
-						return(0);
-					}
-				}
-				ipid++;
-				pnp_c=NULL;
-			} 
-			if (!ipid->card_vendor) {
-				printk(KERN_INFO "Diva PnP: no ISAPnP card found\n");
-			}
-		}
-#endif
-#ifdef CONFIG_PCI
-		cs->subtyp = 0;
-		if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON,
-			PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) {
-			if (pci_enable_device(dev_diva))
-				return(0);
-			cs->subtyp = DIVA_PCI;
-			cs->irq = dev_diva->irq;
-			cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2);
-		} else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON,
-			PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) {
-			if (pci_enable_device(dev_diva_u))
-				return(0);
-			cs->subtyp = DIVA_PCI;
-			cs->irq = dev_diva_u->irq;
-			cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2);
-		} else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON,
-			PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) {
-			if (pci_enable_device(dev_diva201))
-				return(0);
-			cs->subtyp = DIVA_IPAC_PCI;
-			cs->irq = dev_diva201->irq;
-			cs->hw.diva.pci_cfg =
-				(ulong) ioremap(pci_resource_start(dev_diva201, 0), 4096);
-			cs->hw.diva.cfg_reg =
-				(ulong) ioremap(pci_resource_start(dev_diva201, 1), 4096);
-		} else if ((dev_diva202 = pci_find_device(PCI_VENDOR_ID_EICON,
-			PCI_DEVICE_ID_EICON_DIVA202, dev_diva202))) {
-			if (pci_enable_device(dev_diva202))
-				return(0);
-			cs->subtyp = DIVA_IPACX_PCI;
-			cs->irq = dev_diva202->irq;
-			cs->hw.diva.pci_cfg =
-				(ulong) ioremap(pci_resource_start(dev_diva202, 0), 4096);
-			cs->hw.diva.cfg_reg =
-				(ulong) ioremap(pci_resource_start(dev_diva202, 1), 4096);
-		} else {
-			printk(KERN_WARNING "Diva: No PCI card found\n");
-			return(0);
-		}
-
-		if (!cs->irq) {
-			printk(KERN_WARNING "Diva: No IRQ for PCI card found\n");
-			iounmap_diva(cs);
-			return(0);
-		}
-
-		if (!cs->hw.diva.cfg_reg) {
-			printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n");
-			iounmap_diva(cs);
-			return(0);
-		}
-		cs->irq_flags |= IRQF_SHARED;
-#else
-		printk(KERN_WARNING "Diva: cfgreg 0 and NO_PCI_BIOS\n");
-		printk(KERN_WARNING "Diva: unable to config DIVA PCI\n");
-		return (0);
-#endif /* CONFIG_PCI */
-		if ((cs->subtyp == DIVA_IPAC_PCI) ||
-		    (cs->subtyp == DIVA_IPACX_PCI)   ) {
-			cs->hw.diva.ctrl = 0;
-			cs->hw.diva.isac = 0;
-			cs->hw.diva.hscx = 0;
-			cs->hw.diva.isac_adr = 0;
-			cs->hw.diva.hscx_adr = 0;
-			test_and_set_bit(HW_IPAC, &cs->HW_Flags);
-			bytecnt = 0;
-		} else {
-			cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL;
-			cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA;
-			cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA;
-			cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR;
-			cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR;
-			bytecnt = 32;
-		}
-	}
-
-#ifdef __ISAPNP__
-ready:
-#endif
+	if ((cs->subtyp == DIVA_ISA) || (cs->subtyp == DIVA_IPAC_ISA))
+		bytecnt = 8;
+	else
+		bytecnt = 32;
 
 	printk(KERN_INFO
 		"Diva: %s card configured at %#lx IRQ %d\n",
@@ -1145,7 +933,7 @@
 		if (!request_region(cs->hw.diva.cfg_reg, bytecnt, "diva isdn")) {
 			printk(KERN_WARNING
 			       "HiSax: %s config port %lx-%lx already in use\n",
-			       CardType[card->typ],
+			       "diva",
 			       cs->hw.diva.cfg_reg,
 			       cs->hw.diva.cfg_reg + bytecnt);
 			iounmap_diva(cs);
@@ -1206,3 +994,290 @@
 	}
 	return (1);
 }
+
+#ifdef CONFIG_ISA
+
+static int __devinit setup_diva_isa(struct IsdnCard *card)
+{
+	struct IsdnCardState *cs = card->cs;
+	u_char val;
+
+	if (!card->para[1])
+		return (-1);	/* card not found; continue search */
+
+	cs->hw.diva.ctrl_reg = 0;
+	cs->hw.diva.cfg_reg = card->para[1];
+	val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR,
+		cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID);
+	printk(KERN_INFO "Diva: IPAC version %x\n", val);
+	if ((val == 1) || (val==2)) {
+		cs->subtyp = DIVA_IPAC_ISA;
+		cs->hw.diva.ctrl = 0;
+		cs->hw.diva.isac = card->para[1] + DIVA_IPAC_DATA;
+		cs->hw.diva.hscx = card->para[1] + DIVA_IPAC_DATA;
+		cs->hw.diva.isac_adr = card->para[1] + DIVA_IPAC_ADR;
+		cs->hw.diva.hscx_adr = card->para[1] + DIVA_IPAC_ADR;
+		test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+	} else {
+		cs->subtyp = DIVA_ISA;
+		cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL;
+		cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA;
+		cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA;
+		cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR;
+		cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR;
+	}
+	cs->irq = card->para[0];
+
+	return (1);		/* card found */
+}
+
+#else	/* if !CONFIG_ISA */
+
+static int __devinit setup_diva_isa(struct IsdnCard *card)
+{
+	return (-1);	/* card not found; continue search */
+}
+
+#endif	/* CONFIG_ISA */
+
+#ifdef __ISAPNP__
+static struct isapnp_device_id diva_ids[] __devinitdata = {
+	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
+	  ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), 
+	  (unsigned long) "Diva picola" },
+	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
+	  ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x51), 
+	  (unsigned long) "Diva picola" },
+	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
+	  ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), 
+	  (unsigned long) "Diva 2.0" },
+	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
+	  ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x71), 
+	  (unsigned long) "Diva 2.0" },
+	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
+	  ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), 
+	  (unsigned long) "Diva 2.01" },
+	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
+	  ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0xA1), 
+	  (unsigned long) "Diva 2.01" },
+	{ 0, }
+};
+
+static struct isapnp_device_id *ipid __devinitdata = &diva_ids[0];
+static struct pnp_card *pnp_c __devinitdata = NULL;
+
+static int __devinit setup_diva_isapnp(struct IsdnCard *card)
+{
+	struct IsdnCardState *cs = card->cs;
+	struct pnp_dev *pnp_d;
+
+	if (!isapnp_present())
+		return (-1);	/* card not found; continue search */
+
+	while(ipid->card_vendor) {
+		if ((pnp_c = pnp_find_card(ipid->card_vendor,
+			ipid->card_device, pnp_c))) {
+			pnp_d = NULL;
+			if ((pnp_d = pnp_find_dev(pnp_c,
+				ipid->vendor, ipid->function, pnp_d))) {
+				int err;
+
+				printk(KERN_INFO "HiSax: %s detected\n",
+					(char *)ipid->driver_data);
+				pnp_disable_dev(pnp_d);
+				err = pnp_activate_dev(pnp_d);
+				if (err<0) {
+					printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+						__FUNCTION__, err);
+					return(0);
+				}
+				card->para[1] = pnp_port_start(pnp_d, 0);
+				card->para[0] = pnp_irq(pnp_d, 0);
+				if (!card->para[0] || !card->para[1]) {
+					printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n",
+						card->para[0], card->para[1]);
+					pnp_disable_dev(pnp_d); 
+					return(0);
+				}
+				cs->hw.diva.cfg_reg  = card->para[1];
+				cs->irq = card->para[0];
+				if (ipid->function == ISAPNP_FUNCTION(0xA1)) {
+					cs->subtyp = DIVA_IPAC_ISA;
+					cs->hw.diva.ctrl = 0;
+					cs->hw.diva.isac =
+						card->para[1] + DIVA_IPAC_DATA;
+					cs->hw.diva.hscx =
+						card->para[1] + DIVA_IPAC_DATA;
+					cs->hw.diva.isac_adr =
+						card->para[1] + DIVA_IPAC_ADR;
+					cs->hw.diva.hscx_adr =
+						card->para[1] + DIVA_IPAC_ADR;
+					test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+				} else {
+					cs->subtyp = DIVA_ISA;
+					cs->hw.diva.ctrl =
+						card->para[1] + DIVA_ISA_CTRL;
+					cs->hw.diva.isac =
+						card->para[1] + DIVA_ISA_ISAC_DATA;
+					cs->hw.diva.hscx =
+						card->para[1] + DIVA_HSCX_DATA;
+					cs->hw.diva.isac_adr =
+						card->para[1] + DIVA_ISA_ISAC_ADR;
+					cs->hw.diva.hscx_adr =
+						card->para[1] + DIVA_HSCX_ADR;
+				}
+				return (1);		/* card found */
+			} else {
+				printk(KERN_ERR "Diva PnP: PnP error card found, no device\n");
+				return(0);
+			}
+		}
+		ipid++;
+		pnp_c=NULL;
+	} 
+
+	return (-1);	/* card not found; continue search */
+}
+
+#else	/* if !ISAPNP */
+
+static int __devinit setup_diva_isapnp(struct IsdnCard *card)
+{
+	return (-1);	/* card not found; continue search */
+}
+
+#endif	/* ISAPNP */
+
+#ifdef CONFIG_PCI
+static struct pci_dev *dev_diva __devinitdata = NULL;
+static struct pci_dev *dev_diva_u __devinitdata = NULL;
+static struct pci_dev *dev_diva201 __devinitdata = NULL;
+static struct pci_dev *dev_diva202 __devinitdata = NULL;
+
+static int __devinit setup_diva_pci(struct IsdnCard *card)
+{
+	struct IsdnCardState *cs = card->cs;
+
+	cs->subtyp = 0;
+	if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON,
+		PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) {
+		if (pci_enable_device(dev_diva))
+			return(0);
+		cs->subtyp = DIVA_PCI;
+		cs->irq = dev_diva->irq;
+		cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2);
+	} else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON,
+		PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) {
+		if (pci_enable_device(dev_diva_u))
+			return(0);
+		cs->subtyp = DIVA_PCI;
+		cs->irq = dev_diva_u->irq;
+		cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2);
+	} else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON,
+		PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) {
+		if (pci_enable_device(dev_diva201))
+			return(0);
+		cs->subtyp = DIVA_IPAC_PCI;
+		cs->irq = dev_diva201->irq;
+		cs->hw.diva.pci_cfg =
+			(ulong) ioremap(pci_resource_start(dev_diva201, 0), 4096);
+		cs->hw.diva.cfg_reg =
+			(ulong) ioremap(pci_resource_start(dev_diva201, 1), 4096);
+	} else if ((dev_diva202 = pci_find_device(PCI_VENDOR_ID_EICON,
+		PCI_DEVICE_ID_EICON_DIVA202, dev_diva202))) {
+		if (pci_enable_device(dev_diva202))
+			return(0);
+		cs->subtyp = DIVA_IPACX_PCI;
+		cs->irq = dev_diva202->irq;
+		cs->hw.diva.pci_cfg =
+			(ulong) ioremap(pci_resource_start(dev_diva202, 0), 4096);
+		cs->hw.diva.cfg_reg =
+			(ulong) ioremap(pci_resource_start(dev_diva202, 1), 4096);
+	} else {
+		return (-1);	/* card not found; continue search */
+	}
+
+	if (!cs->irq) {
+		printk(KERN_WARNING "Diva: No IRQ for PCI card found\n");
+		iounmap_diva(cs);
+		return(0);
+	}
+
+	if (!cs->hw.diva.cfg_reg) {
+		printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n");
+		iounmap_diva(cs);
+		return(0);
+	}
+	cs->irq_flags |= IRQF_SHARED;
+
+	if ((cs->subtyp == DIVA_IPAC_PCI) ||
+	    (cs->subtyp == DIVA_IPACX_PCI)   ) {
+		cs->hw.diva.ctrl = 0;
+		cs->hw.diva.isac = 0;
+		cs->hw.diva.hscx = 0;
+		cs->hw.diva.isac_adr = 0;
+		cs->hw.diva.hscx_adr = 0;
+		test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+	} else {
+		cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL;
+		cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA;
+		cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA;
+		cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR;
+		cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR;
+	}
+
+	return (1);		/* card found */
+}
+
+#else	/* if !CONFIG_PCI */
+
+static int __devinit setup_diva_pci(struct IsdnCard *card)
+{
+	return (-1);	/* card not found; continue search */
+}
+
+#endif	/* CONFIG_PCI */
+
+int __devinit
+setup_diva(struct IsdnCard *card)
+{
+	int rc, have_card = 0;
+	struct IsdnCardState *cs = card->cs;
+	char tmp[64];
+
+	strcpy(tmp, Diva_revision);
+	printk(KERN_INFO "HiSax: Eicon.Diehl Diva driver Rev. %s\n", HiSax_getrev(tmp));
+	if (cs->typ != ISDN_CTYPE_DIEHLDIVA)
+		return(0);
+	cs->hw.diva.status = 0;
+
+	rc = setup_diva_isa(card);
+	if (!rc)
+		return rc;
+	if (rc > 0) {
+		have_card = 1;
+		goto ready;
+	}
+
+	rc = setup_diva_isapnp(card);
+	if (!rc)
+		return rc;
+	if (rc > 0) {
+		have_card = 1;
+		goto ready;
+	}
+
+	rc = setup_diva_pci(card);
+	if (!rc)
+		return rc;
+	if (rc > 0)
+		have_card = 1;
+
+ready:
+	if (!have_card) {
+		printk(KERN_WARNING "Diva: No ISA, ISAPNP or PCI card found\n");
+		return(0);
+	}
+
+	return setup_diva_common(card->cs);
+}
diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c
index fab3e4e..0c1351b 100644
--- a/drivers/isdn/hisax/elsa.c
+++ b/drivers/isdn/hisax/elsa.c
@@ -30,8 +30,6 @@
 #include <linux/serial.h>
 #include <linux/serial_reg.h>
 
-extern const char *CardType[];
-
 static const char *Elsa_revision = "$Revision: 2.32.2.4 $";
 static const char *Elsa_Types[] =
 {"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro",
@@ -832,8 +830,75 @@
 	return (CARD_portlist[i]);
 }
 
-static 	struct pci_dev *dev_qs1000 __devinitdata = NULL;
-static 	struct pci_dev *dev_qs3000 __devinitdata = NULL;
+static int __devinit
+setup_elsa_isa(struct IsdnCard *card)
+{
+	struct IsdnCardState *cs = card->cs;
+	u_char val;
+
+	cs->hw.elsa.base = card->para[0];
+	printk(KERN_INFO "Elsa: Microlink IO probing\n");
+	if (cs->hw.elsa.base) {
+		if (!(cs->subtyp = probe_elsa_adr(cs->hw.elsa.base,
+						  cs->typ))) {
+			printk(KERN_WARNING
+			       "Elsa: no Elsa Microlink at %#lx\n",
+			       cs->hw.elsa.base);
+			return (0);
+		}
+	} else
+		cs->hw.elsa.base = probe_elsa(cs);
+
+	if (!cs->hw.elsa.base) {
+		printk(KERN_WARNING
+		       "No Elsa Microlink found\n");
+		return (0);
+	}
+
+	cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
+	cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
+	cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
+	cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
+	cs->hw.elsa.itac = cs->hw.elsa.base + ELSA_ITAC;
+	cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
+	cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
+	cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
+	val = bytein(cs->hw.elsa.cfg);
+	if (cs->subtyp == ELSA_PC) {
+		const u_char CARD_IrqTab[8] =
+		{7, 3, 5, 9, 0, 0, 0, 0};
+		cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2];
+	} else if (cs->subtyp == ELSA_PCC8) {
+		const u_char CARD_IrqTab[8] =
+		{7, 3, 5, 9, 0, 0, 0, 0};
+		cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PCC8) >> 4];
+	} else {
+		const u_char CARD_IrqTab[8] =
+		{15, 10, 15, 3, 11, 5, 11, 9};
+		cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX) >> 3];
+	}
+	val = bytein(cs->hw.elsa.ale) & ELSA_HW_RELEASE;
+	if (val < 3)
+		val |= 8;
+	val += 'A' - 3;
+	if (val == 'B' || val == 'C')
+		val ^= 1;
+	if ((cs->subtyp == ELSA_PCFPRO) && (val = 'G'))
+		val = 'C';
+	printk(KERN_INFO
+	       "Elsa: %s found at %#lx Rev.:%c IRQ %d\n",
+	       Elsa_Types[cs->subtyp],
+	       cs->hw.elsa.base,
+	       val, cs->irq);
+	val = bytein(cs->hw.elsa.ale) & ELSA_S0_POWER_BAD;
+	if (val) {
+		printk(KERN_WARNING
+		   "Elsa: Microlink S0 bus power bad\n");
+		cs->hw.elsa.status |= ELSA_BAD_PWR;
+	}
+
+	return (1);
+}
 
 #ifdef __ISAPNP__
 static struct isapnp_device_id elsa_ids[] __devinitdata = {
@@ -848,233 +913,194 @@
 
 static struct isapnp_device_id *ipid __devinitdata = &elsa_ids[0];
 static struct pnp_card *pnp_c __devinitdata = NULL;
-#endif
+#endif	/* __ISAPNP__ */
 
-int __devinit
-setup_elsa(struct IsdnCard *card)
+static int __devinit
+setup_elsa_isapnp(struct IsdnCard *card)
 {
-	int bytecnt;
-	u_char val;
 	struct IsdnCardState *cs = card->cs;
-	char tmp[64];
 
-	strcpy(tmp, Elsa_revision);
-	printk(KERN_INFO "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp));
-	cs->hw.elsa.ctrl_reg = 0;
-	cs->hw.elsa.status = 0;
-	cs->hw.elsa.MFlag = 0;
-	cs->subtyp = 0;
-	if (cs->typ == ISDN_CTYPE_ELSA) {
-		cs->hw.elsa.base = card->para[0];
-		printk(KERN_INFO "Elsa: Microlink IO probing\n");
-		if (cs->hw.elsa.base) {
-			if (!(cs->subtyp = probe_elsa_adr(cs->hw.elsa.base,
-							  cs->typ))) {
-				printk(KERN_WARNING
-				       "Elsa: no Elsa Microlink at %#lx\n",
-				       cs->hw.elsa.base);
-				return (0);
-			}
-		} else
-			cs->hw.elsa.base = probe_elsa(cs);
-		if (cs->hw.elsa.base) {
-			cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
-			cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
-			cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
-			cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
-			cs->hw.elsa.itac = cs->hw.elsa.base + ELSA_ITAC;
-			cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
-			cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
-			cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
-			val = bytein(cs->hw.elsa.cfg);
-			if (cs->subtyp == ELSA_PC) {
-				const u_char CARD_IrqTab[8] =
-				{7, 3, 5, 9, 0, 0, 0, 0};
-				cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2];
-			} else if (cs->subtyp == ELSA_PCC8) {
-				const u_char CARD_IrqTab[8] =
-				{7, 3, 5, 9, 0, 0, 0, 0};
-				cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PCC8) >> 4];
-			} else {
-				const u_char CARD_IrqTab[8] =
-				{15, 10, 15, 3, 11, 5, 11, 9};
-				cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX) >> 3];
-			}
-			val = bytein(cs->hw.elsa.ale) & ELSA_HW_RELEASE;
-			if (val < 3)
-				val |= 8;
-			val += 'A' - 3;
-			if (val == 'B' || val == 'C')
-				val ^= 1;
-			if ((cs->subtyp == ELSA_PCFPRO) && (val = 'G'))
-				val = 'C';
-			printk(KERN_INFO
-			       "Elsa: %s found at %#lx Rev.:%c IRQ %d\n",
-			       Elsa_Types[cs->subtyp],
-			       cs->hw.elsa.base,
-			       val, cs->irq);
-			val = bytein(cs->hw.elsa.ale) & ELSA_S0_POWER_BAD;
-			if (val) {
-				printk(KERN_WARNING
-				   "Elsa: Microlink S0 bus power bad\n");
-				cs->hw.elsa.status |= ELSA_BAD_PWR;
-			}
-		} else {
-			printk(KERN_WARNING
-			       "No Elsa Microlink found\n");
-			return (0);
-		}
-	} else if (cs->typ == ISDN_CTYPE_ELSA_PNP) {
 #ifdef __ISAPNP__
-		if (!card->para[1] && isapnp_present()) {
-			struct pnp_dev *pnp_d;
-			while(ipid->card_vendor) {
-				if ((pnp_c = pnp_find_card(ipid->card_vendor,
-					ipid->card_device, pnp_c))) {
-					pnp_d = NULL;
-					if ((pnp_d = pnp_find_dev(pnp_c,
-						ipid->vendor, ipid->function, pnp_d))) {
-						int err;
+	if (!card->para[1] && isapnp_present()) {
+		struct pnp_dev *pnp_d;
+		while(ipid->card_vendor) {
+			if ((pnp_c = pnp_find_card(ipid->card_vendor,
+				ipid->card_device, pnp_c))) {
+				pnp_d = NULL;
+				if ((pnp_d = pnp_find_dev(pnp_c,
+					ipid->vendor, ipid->function, pnp_d))) {
+					int err;
 
-						printk(KERN_INFO "HiSax: %s detected\n",
-							(char *)ipid->driver_data);
-						pnp_disable_dev(pnp_d);
-						err = pnp_activate_dev(pnp_d);
-						if (err<0) {
-							printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
-								__FUNCTION__, err);
-							return(0);
-						}
-						card->para[1] = pnp_port_start(pnp_d, 0);
-						card->para[0] = pnp_irq(pnp_d, 0);
-
-						if (!card->para[0] || !card->para[1]) {
-							printk(KERN_ERR "Elsa PnP:some resources are missing %ld/%lx\n",
-								card->para[0], card->para[1]);
-							pnp_disable_dev(pnp_d);
-							return(0);
-						}
-						if (ipid->function == ISAPNP_FUNCTION(0x133))
-							cs->subtyp = ELSA_QS1000;
-						else
-							cs->subtyp = ELSA_QS3000;
-						break;
-					} else {
-						printk(KERN_ERR "Elsa PnP: PnP error card found, no device\n");
+					printk(KERN_INFO "HiSax: %s detected\n",
+						(char *)ipid->driver_data);
+					pnp_disable_dev(pnp_d);
+					err = pnp_activate_dev(pnp_d);
+					if (err<0) {
+						printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+							__FUNCTION__, err);
 						return(0);
 					}
+					card->para[1] = pnp_port_start(pnp_d, 0);
+					card->para[0] = pnp_irq(pnp_d, 0);
+
+					if (!card->para[0] || !card->para[1]) {
+						printk(KERN_ERR "Elsa PnP:some resources are missing %ld/%lx\n",
+							card->para[0], card->para[1]);
+						pnp_disable_dev(pnp_d);
+						return(0);
+					}
+					if (ipid->function == ISAPNP_FUNCTION(0x133))
+						cs->subtyp = ELSA_QS1000;
+					else
+						cs->subtyp = ELSA_QS3000;
+					break;
+				} else {
+					printk(KERN_ERR "Elsa PnP: PnP error card found, no device\n");
+					return(0);
 				}
-				ipid++;
-				pnp_c=NULL;
-			} 
-			if (!ipid->card_vendor) {
-				printk(KERN_INFO "Elsa PnP: no ISAPnP card found\n");
-				return(0);
 			}
+			ipid++;
+			pnp_c=NULL;
+		} 
+		if (!ipid->card_vendor) {
+			printk(KERN_INFO "Elsa PnP: no ISAPnP card found\n");
+			return(0);
 		}
-#endif
-		if (card->para[1] && card->para[0]) { 
-			cs->hw.elsa.base = card->para[1];
-			cs->irq = card->para[0];
-			if (!cs->subtyp)
-				cs->subtyp = ELSA_QS1000;
-		} else {
-			printk(KERN_ERR "Elsa PnP: no parameter\n");
-		}
-		cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
-		cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
-		cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
-		cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
-		cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
-		cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
-		cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
-		printk(KERN_INFO
-		       "Elsa: %s defined at %#lx IRQ %d\n",
-		       Elsa_Types[cs->subtyp],
-		       cs->hw.elsa.base,
-		       cs->irq);
-	} else if (cs->typ == ISDN_CTYPE_ELSA_PCMCIA) {
+	}
+#endif	/* __ISAPNP__ */
+
+	if (card->para[1] && card->para[0]) { 
 		cs->hw.elsa.base = card->para[1];
 		cs->irq = card->para[0];
-		val = readreg(cs->hw.elsa.base + 0, cs->hw.elsa.base + 2, IPAC_ID);
-		if ((val == 1) || (val == 2)) { /* IPAC version 1.1/1.2 */
-			cs->subtyp = ELSA_PCMCIA_IPAC;
-			cs->hw.elsa.ale = cs->hw.elsa.base + 0;
-			cs->hw.elsa.isac = cs->hw.elsa.base + 2;
-			cs->hw.elsa.hscx = cs->hw.elsa.base + 2;
-			test_and_set_bit(HW_IPAC, &cs->HW_Flags);
-		} else {
-			cs->subtyp = ELSA_PCMCIA;
-			cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE_PCM;
-			cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC_PCM;
-			cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
-		}
-		cs->hw.elsa.timer = 0;
-		cs->hw.elsa.trig = 0;
-		cs->hw.elsa.ctrl = 0;
-		cs->irq_flags |= IRQF_SHARED;
-		printk(KERN_INFO
-		       "Elsa: %s defined at %#lx IRQ %d\n",
-		       Elsa_Types[cs->subtyp],
-		       cs->hw.elsa.base,
-		       cs->irq);
-	} else if (cs->typ == ISDN_CTYPE_ELSA_PCI) {
-#ifdef CONFIG_PCI
-		cs->subtyp = 0;
-		if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA,
-			PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) {
-			if (pci_enable_device(dev_qs1000))
-				return(0);
-			cs->subtyp = ELSA_QS1000PCI;
-			cs->irq = dev_qs1000->irq;
-			cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1);
-			cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3);
-		} else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ID_ELSA,
-			PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) {
-			if (pci_enable_device(dev_qs3000))
-				return(0);
-			cs->subtyp = ELSA_QS3000PCI;
-			cs->irq = dev_qs3000->irq;
-			cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1);
-			cs->hw.elsa.base = pci_resource_start(dev_qs3000, 3);
-		} else {
-			printk(KERN_WARNING "Elsa: No PCI card found\n");
-			return(0);
-		}
-		if (!cs->irq) {
-			printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n");
-			return(0);
-		}
+		if (!cs->subtyp)
+			cs->subtyp = ELSA_QS1000;
+	} else {
+		printk(KERN_ERR "Elsa PnP: no parameter\n");
+	}
+	cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
+	cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
+	cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
+	cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
+	cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
+	cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
+	cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
+	printk(KERN_INFO
+	       "Elsa: %s defined at %#lx IRQ %d\n",
+	       Elsa_Types[cs->subtyp],
+	       cs->hw.elsa.base,
+	       cs->irq);
 
-		if (!(cs->hw.elsa.base && cs->hw.elsa.cfg)) {
-			printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n");
-			return(0);
-		}
-		if ((cs->hw.elsa.cfg & 0xff) || (cs->hw.elsa.base & 0xf)) {
-			printk(KERN_WARNING "Elsa: You may have a wrong PCI bios\n");
-			printk(KERN_WARNING "Elsa: If your system hangs now, read\n");
-			printk(KERN_WARNING "Elsa: Documentation/isdn/README.HiSax\n");
-		}
-		cs->hw.elsa.ale  = cs->hw.elsa.base;
-		cs->hw.elsa.isac = cs->hw.elsa.base +1;
-		cs->hw.elsa.hscx = cs->hw.elsa.base +1; 
+	return (1);
+}
+
+static void __devinit
+setup_elsa_pcmcia(struct IsdnCard *card)
+{
+	struct IsdnCardState *cs = card->cs;
+	u_char val;
+
+	cs->hw.elsa.base = card->para[1];
+	cs->irq = card->para[0];
+	val = readreg(cs->hw.elsa.base + 0, cs->hw.elsa.base + 2, IPAC_ID);
+	if ((val == 1) || (val == 2)) { /* IPAC version 1.1/1.2 */
+		cs->subtyp = ELSA_PCMCIA_IPAC;
+		cs->hw.elsa.ale = cs->hw.elsa.base + 0;
+		cs->hw.elsa.isac = cs->hw.elsa.base + 2;
+		cs->hw.elsa.hscx = cs->hw.elsa.base + 2;
 		test_and_set_bit(HW_IPAC, &cs->HW_Flags);
-		cs->hw.elsa.timer = 0;
-		cs->hw.elsa.trig  = 0;
-		cs->irq_flags |= IRQF_SHARED;
-		printk(KERN_INFO
-		       "Elsa: %s defined at %#lx/0x%x IRQ %d\n",
-		       Elsa_Types[cs->subtyp],
-		       cs->hw.elsa.base,
-		       cs->hw.elsa.cfg,
-		       cs->irq);
+	} else {
+		cs->subtyp = ELSA_PCMCIA;
+		cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE_PCM;
+		cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC_PCM;
+		cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
+	}
+	cs->hw.elsa.timer = 0;
+	cs->hw.elsa.trig = 0;
+	cs->hw.elsa.ctrl = 0;
+	cs->irq_flags |= IRQF_SHARED;
+	printk(KERN_INFO
+	       "Elsa: %s defined at %#lx IRQ %d\n",
+	       Elsa_Types[cs->subtyp],
+	       cs->hw.elsa.base,
+	       cs->irq);
+}
+
+#ifdef CONFIG_PCI
+static 	struct pci_dev *dev_qs1000 __devinitdata = NULL;
+static 	struct pci_dev *dev_qs3000 __devinitdata = NULL;
+
+static int __devinit
+setup_elsa_pci(struct IsdnCard *card)
+{
+	struct IsdnCardState *cs = card->cs;
+
+	cs->subtyp = 0;
+	if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA,
+		PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) {
+		if (pci_enable_device(dev_qs1000))
+			return(0);
+		cs->subtyp = ELSA_QS1000PCI;
+		cs->irq = dev_qs1000->irq;
+		cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1);
+		cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3);
+	} else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ID_ELSA,
+		PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) {
+		if (pci_enable_device(dev_qs3000))
+			return(0);
+		cs->subtyp = ELSA_QS3000PCI;
+		cs->irq = dev_qs3000->irq;
+		cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1);
+		cs->hw.elsa.base = pci_resource_start(dev_qs3000, 3);
+	} else {
+		printk(KERN_WARNING "Elsa: No PCI card found\n");
+		return(0);
+	}
+	if (!cs->irq) {
+		printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n");
+		return(0);
+	}
+
+	if (!(cs->hw.elsa.base && cs->hw.elsa.cfg)) {
+		printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n");
+		return(0);
+	}
+	if ((cs->hw.elsa.cfg & 0xff) || (cs->hw.elsa.base & 0xf)) {
+		printk(KERN_WARNING "Elsa: You may have a wrong PCI bios\n");
+		printk(KERN_WARNING "Elsa: If your system hangs now, read\n");
+		printk(KERN_WARNING "Elsa: Documentation/isdn/README.HiSax\n");
+	}
+	cs->hw.elsa.ale  = cs->hw.elsa.base;
+	cs->hw.elsa.isac = cs->hw.elsa.base +1;
+	cs->hw.elsa.hscx = cs->hw.elsa.base +1; 
+	test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+	cs->hw.elsa.timer = 0;
+	cs->hw.elsa.trig  = 0;
+	cs->irq_flags |= IRQF_SHARED;
+	printk(KERN_INFO
+	       "Elsa: %s defined at %#lx/0x%x IRQ %d\n",
+	       Elsa_Types[cs->subtyp],
+	       cs->hw.elsa.base,
+	       cs->hw.elsa.cfg,
+	       cs->irq);
+
+	return (1);
+}
+
 #else
-		printk(KERN_WARNING "Elsa: Elsa PCI and NO_PCI_BIOS\n");
-		printk(KERN_WARNING "Elsa: unable to config Elsa PCI\n");
-		return (0);
+
+static void __devinit
+setup_elsa_pci(struct IsdnCard *card)
+{
+	return (1);
+}
 #endif /* CONFIG_PCI */
-	} else 
-		return (0);
+
+static int __devinit
+setup_elsa_common(struct IsdnCard *card)
+{
+	struct IsdnCardState *cs = card->cs;
+	u_char val;
+	int bytecnt;
 
 	switch (cs->subtyp) {
 		case ELSA_PC:
@@ -1104,8 +1130,7 @@
 	   here, it would fail. */
 	if (cs->typ != ISDN_CTYPE_ELSA_PCMCIA && !request_region(cs->hw.elsa.base, bytecnt, "elsa isdn")) {
 		printk(KERN_WARNING
-		       "HiSax: %s config port %#lx-%#lx already in use\n",
-		       CardType[card->typ],
+		       "HiSax: ELSA config port %#lx-%#lx already in use\n",
 		       cs->hw.elsa.base,
 		       cs->hw.elsa.base + bytecnt);
 		return (0);
@@ -1113,8 +1138,7 @@
 	if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI)) {
 		if (!request_region(cs->hw.elsa.cfg, 0x80, "elsa isdn pci")) {
 			printk(KERN_WARNING
-			       "HiSax: %s pci port %x-%x already in use\n",
-				CardType[card->typ],
+			       "HiSax: ELSA pci port %x-%x already in use\n",
 				cs->hw.elsa.cfg,
 				cs->hw.elsa.cfg + 0x80);
 			release_region(cs->hw.elsa.base, bytecnt);
@@ -1186,3 +1210,41 @@
 	}
 	return (1);
 }
+
+int __devinit
+setup_elsa(struct IsdnCard *card)
+{
+	int rc;
+	struct IsdnCardState *cs = card->cs;
+	char tmp[64];
+
+	strcpy(tmp, Elsa_revision);
+	printk(KERN_INFO "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp));
+	cs->hw.elsa.ctrl_reg = 0;
+	cs->hw.elsa.status = 0;
+	cs->hw.elsa.MFlag = 0;
+	cs->subtyp = 0;
+
+	if (cs->typ == ISDN_CTYPE_ELSA) {
+		rc = setup_elsa_isa(card);
+		if (!rc)
+			return (0);
+
+	} else if (cs->typ == ISDN_CTYPE_ELSA_PNP) {
+		rc = setup_elsa_isapnp(card);
+		if (!rc)
+			return (0);
+
+	} else if (cs->typ == ISDN_CTYPE_ELSA_PCMCIA)
+		setup_elsa_pcmcia(card);
+
+	else if (cs->typ == ISDN_CTYPE_ELSA_PCI) {
+		rc = setup_elsa_pci(card);
+		if (!rc)
+			return (0);
+
+	} else 
+		return (0);
+
+	return setup_elsa_common(card);
+}
diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c
index ad06f3c..03dfc32 100644
--- a/drivers/isdn/hisax/sedlbauer.c
+++ b/drivers/isdn/hisax/sedlbauer.c
@@ -518,8 +518,6 @@
 	return(0);
 }
 
-static struct pci_dev *dev_sedl __devinitdata = NULL;
-
 #ifdef __ISAPNP__
 static struct isapnp_device_id sedl_ids[] __devinitdata = {
 	{ ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x01),
@@ -533,15 +531,158 @@
 
 static struct isapnp_device_id *ipid __devinitdata = &sedl_ids[0];
 static struct pnp_card *pnp_c __devinitdata = NULL;
-#endif
+
+static int __devinit
+setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt)
+{
+	struct IsdnCardState *cs = card->cs;
+	struct pnp_dev *pnp_d;
+
+	if (!isapnp_present())
+		return -1;
+
+	while(ipid->card_vendor) {
+		if ((pnp_c = pnp_find_card(ipid->card_vendor,
+			ipid->card_device, pnp_c))) {
+			pnp_d = NULL;
+			if ((pnp_d = pnp_find_dev(pnp_c,
+				ipid->vendor, ipid->function, pnp_d))) {
+				int err;
+
+				printk(KERN_INFO "HiSax: %s detected\n",
+					(char *)ipid->driver_data);
+				pnp_disable_dev(pnp_d);
+				err = pnp_activate_dev(pnp_d);
+				if (err<0) {
+					printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+						__FUNCTION__, err);
+					return(0);
+				}
+				card->para[1] = pnp_port_start(pnp_d, 0);
+				card->para[0] = pnp_irq(pnp_d, 0);
+
+				if (!card->para[0] || !card->para[1]) {
+					printk(KERN_ERR "Sedlbauer PnP:some resources are missing %ld/%lx\n",
+						card->para[0], card->para[1]);
+					pnp_disable_dev(pnp_d);
+					return(0);
+				}
+				cs->hw.sedl.cfg_reg = card->para[1];
+				cs->irq = card->para[0];
+				if (ipid->function == ISAPNP_FUNCTION(0x2)) {
+					cs->subtyp = SEDL_SPEED_FAX;
+					cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
+					*bytecnt = 16;
+				} else {
+					cs->subtyp = SEDL_SPEED_CARD_WIN;
+					cs->hw.sedl.chip = SEDL_CHIP_TEST;
+				}
+
+				return (1);
+			} else {
+				printk(KERN_ERR "Sedlbauer PnP: PnP error card found, no device\n");
+				return(0);
+			}
+		}
+		ipid++;
+		pnp_c = NULL;
+	} 
+
+	printk(KERN_INFO "Sedlbauer PnP: no ISAPnP card found\n");
+	return -1;
+}
+#else
+
+static int __devinit
+setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt)
+{
+	return -1;
+}
+#endif /* __ISAPNP__ */
+
+#ifdef CONFIG_PCI
+static struct pci_dev *dev_sedl __devinitdata = NULL;
+
+static int __devinit
+setup_sedlbauer_pci(struct IsdnCard *card)
+{
+	struct IsdnCardState *cs = card->cs;
+	u16 sub_vendor_id, sub_id;
+
+	if ((dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET,
+			PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) {
+		if (pci_enable_device(dev_sedl))
+			return(0);
+		cs->irq = dev_sedl->irq;
+		if (!cs->irq) {
+			printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n");
+			return(0);
+		}
+		cs->hw.sedl.cfg_reg = pci_resource_start(dev_sedl, 0);
+	} else {
+		printk(KERN_WARNING "Sedlbauer: No PCI card found\n");
+		return(0);
+	}
+	cs->irq_flags |= IRQF_SHARED;
+	cs->hw.sedl.bus = SEDL_BUS_PCI;
+	sub_vendor_id = dev_sedl->subsystem_vendor;
+	sub_id = dev_sedl->subsystem_device;
+	printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n",
+		sub_vendor_id, sub_id);
+	printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n",
+		cs->hw.sedl.cfg_reg);
+	if (sub_id != PCI_SUB_ID_SEDLBAUER) {
+		printk(KERN_ERR "Sedlbauer: unknown sub id %#x\n", sub_id);
+		return(0);
+	}
+	if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PYRAMID) {
+		cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
+		cs->subtyp = SEDL_SPEEDFAX_PYRAMID;
+	} else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) {
+		cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
+		cs->subtyp = SEDL_SPEEDFAX_PCI;
+	} else if (sub_vendor_id == PCI_SUBVENDOR_HST_SAPHIR3) {
+		cs->hw.sedl.chip = SEDL_CHIP_IPAC;
+		cs->subtyp = HST_SAPHIR3;
+	} else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) {
+		cs->hw.sedl.chip = SEDL_CHIP_IPAC;
+		cs->subtyp = SEDL_SPEED_PCI;
+	} else {
+		printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n",
+			sub_vendor_id);
+		return(0);
+	}
+
+	cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON;
+	cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF;
+	byteout(cs->hw.sedl.cfg_reg, 0xff);
+	byteout(cs->hw.sedl.cfg_reg, 0x00);
+	byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd);
+	byteout(cs->hw.sedl.cfg_reg+ 5, 0); /* disable all IRQ */
+	byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on);
+	mdelay(2);
+	byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
+	mdelay(10);
+
+	return (1);
+}
+
+#else
+
+static int __devinit
+setup_sedlbauer_pci(struct IsdnCard *card)
+{
+	return (1);
+}
+
+#endif /* CONFIG_PCI */
 
 int __devinit
 setup_sedlbauer(struct IsdnCard *card)
 {
-	int bytecnt, ver, val;
+	int bytecnt = 8, ver, val, rc;
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
-	u16 sub_vendor_id, sub_id;
 
 	strcpy(tmp, Sedlbauer_revision);
 	printk(KERN_INFO "HiSax: Sedlbauer driver Rev. %s\n", HiSax_getrev(tmp));
@@ -569,124 +710,21 @@
 			bytecnt = 16;
 		}
 	} else {
-#ifdef __ISAPNP__
-		if (isapnp_present()) {
-			struct pnp_dev *pnp_d;
-			while(ipid->card_vendor) {
-				if ((pnp_c = pnp_find_card(ipid->card_vendor,
-					ipid->card_device, pnp_c))) {
-					pnp_d = NULL;
-					if ((pnp_d = pnp_find_dev(pnp_c,
-						ipid->vendor, ipid->function, pnp_d))) {
-						int err;
+		rc = setup_sedlbauer_isapnp(card, &bytecnt);
+		if (!rc)
+			return (0);
+		if (rc > 0)
+			goto ready;
 
-						printk(KERN_INFO "HiSax: %s detected\n",
-							(char *)ipid->driver_data);
-						pnp_disable_dev(pnp_d);
-						err = pnp_activate_dev(pnp_d);
-						if (err<0) {
-							printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
-								__FUNCTION__, err);
-							return(0);
-						}
-						card->para[1] = pnp_port_start(pnp_d, 0);
-						card->para[0] = pnp_irq(pnp_d, 0);
+		/* Probe for Sedlbauer speed pci */
+		rc = setup_sedlbauer_pci(card);
+		if (!rc)
+			return (0);
 
-						if (!card->para[0] || !card->para[1]) {
-							printk(KERN_ERR "Sedlbauer PnP:some resources are missing %ld/%lx\n",
-								card->para[0], card->para[1]);
-							pnp_disable_dev(pnp_d);
-							return(0);
-						}
-						cs->hw.sedl.cfg_reg = card->para[1];
-						cs->irq = card->para[0];
-						if (ipid->function == ISAPNP_FUNCTION(0x2)) {
-							cs->subtyp = SEDL_SPEED_FAX;
-							cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
-							bytecnt = 16;
-						} else {
-							cs->subtyp = SEDL_SPEED_CARD_WIN;
-							cs->hw.sedl.chip = SEDL_CHIP_TEST;
-						}
-						goto ready;
-					} else {
-						printk(KERN_ERR "Sedlbauer PnP: PnP error card found, no device\n");
-						return(0);
-					}
-				}
-				ipid++;
-				pnp_c = NULL;
-			} 
-			if (!ipid->card_vendor) {
-				printk(KERN_INFO "Sedlbauer PnP: no ISAPnP card found\n");
-			}
-		}
-#endif
-/* Probe for Sedlbauer speed pci */
-#ifdef CONFIG_PCI
-		if ((dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET,
-				PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) {
-			if (pci_enable_device(dev_sedl))
-				return(0);
-			cs->irq = dev_sedl->irq;
-			if (!cs->irq) {
-				printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n");
-				return(0);
-			}
-			cs->hw.sedl.cfg_reg = pci_resource_start(dev_sedl, 0);
-		} else {
-			printk(KERN_WARNING "Sedlbauer: No PCI card found\n");
-			return(0);
-		}
-		cs->irq_flags |= IRQF_SHARED;
-		cs->hw.sedl.bus = SEDL_BUS_PCI;
-		sub_vendor_id = dev_sedl->subsystem_vendor;
-		sub_id = dev_sedl->subsystem_device;
-		printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n",
-			sub_vendor_id, sub_id);
-		printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n",
-			cs->hw.sedl.cfg_reg);
-		if (sub_id != PCI_SUB_ID_SEDLBAUER) {
-			printk(KERN_ERR "Sedlbauer: unknown sub id %#x\n", sub_id);
-			return(0);
-		}
-		if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PYRAMID) {
-			cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
-			cs->subtyp = SEDL_SPEEDFAX_PYRAMID;
-		} else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) {
-			cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
-			cs->subtyp = SEDL_SPEEDFAX_PCI;
-		} else if (sub_vendor_id == PCI_SUBVENDOR_HST_SAPHIR3) {
-			cs->hw.sedl.chip = SEDL_CHIP_IPAC;
-			cs->subtyp = HST_SAPHIR3;
-		} else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) {
-			cs->hw.sedl.chip = SEDL_CHIP_IPAC;
-			cs->subtyp = SEDL_SPEED_PCI;
-		} else {
-			printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n",
-				sub_vendor_id);
-			return(0);
-		}
 		bytecnt = 256;
-		cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON;
-		cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF;
-		byteout(cs->hw.sedl.cfg_reg, 0xff);
-		byteout(cs->hw.sedl.cfg_reg, 0x00);
-		byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd);
-		byteout(cs->hw.sedl.cfg_reg+ 5, 0); /* disable all IRQ */
-		byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on);
-		mdelay(2);
-		byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
-		mdelay(10);
-#else
-		printk(KERN_WARNING "Sedlbauer: NO_PCI_BIOS\n");
-		return (0);
-#endif /* CONFIG_PCI */
 	}	
 
-#ifdef __ISAPNP__
 ready:	
-#endif
 
 	/* In case of the sedlbauer pcmcia card, this region is in use,
 	 * reserved for us by the card manager. So we do not check it
diff --git a/drivers/isdn/hisax/telespci.c b/drivers/isdn/hisax/telespci.c
index d09f6d0..4393003 100644
--- a/drivers/isdn/hisax/telespci.c
+++ b/drivers/isdn/hisax/telespci.c
@@ -295,11 +295,12 @@
 #ifdef __BIG_ENDIAN
 #error "not running on big endian machines now"
 #endif
+
 	strcpy(tmp, telespci_revision);
 	printk(KERN_INFO "HiSax: Teles/PCI driver Rev. %s\n", HiSax_getrev(tmp));
 	if (cs->typ != ISDN_CTYPE_TELESPCI)
 		return (0);
-#ifdef CONFIG_PCI
+
 	if ((dev_tel = pci_find_device (PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, dev_tel))) {
 		if (pci_enable_device(dev_tel))
 			return(0);
@@ -317,11 +318,6 @@
 		printk(KERN_WARNING "TelesPCI: No PCI card found\n");
 		return(0);
 	}
-#else
-	printk(KERN_WARNING "HiSax: Teles/PCI and NO_PCI_BIOS\n");
-	printk(KERN_WARNING "HiSax: Teles/PCI unable to config\n");
-	return (0);
-#endif /* CONFIG_PCI */
 
 	/* Initialize Zoran PCI controller */
 	writel(0x00000000, cs->hw.teles0.membase + 0x28);
diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c
index 3aeceaf..39129b9 100644
--- a/drivers/isdn/hisax/w6692.c
+++ b/drivers/isdn/hisax/w6692.c
@@ -1009,7 +1009,7 @@
 	printk(KERN_INFO "HiSax: W6692 driver Rev. %s\n", HiSax_getrev(tmp));
 	if (cs->typ != ISDN_CTYPE_W6692)
 		return (0);
-#ifdef CONFIG_PCI
+
 	while (id_list[id_idx].vendor_id) {
 		dev_w6692 = pci_find_device(id_list[id_idx].vendor_id,
 					    id_list[id_idx].device_id,
@@ -1061,11 +1061,6 @@
 		       cs->hw.w6692.iobase + 255);
 		return (0);
 	}
-#else
-	printk(KERN_WARNING "HiSax: W6692 and NO_PCI_BIOS\n");
-	printk(KERN_WARNING "HiSax: W6692 unable to config\n");
-	return (0);
-#endif				/* CONFIG_PCI */
 
 	printk(KERN_INFO
 	       "HiSax: %s config irq:%d I/O:%x\n",
diff --git a/drivers/isdn/hysdn/hysdn_init.c b/drivers/isdn/hysdn/hysdn_init.c
index 9e01748..b7cc5c2 100644
--- a/drivers/isdn/hysdn/hysdn_init.c
+++ b/drivers/isdn/hysdn/hysdn_init.c
@@ -20,10 +20,15 @@
 #include "hysdn_defs.h"
 
 static struct pci_device_id hysdn_pci_tbl[] = {
-	{PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_METRO},
-	{PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2},
-	{PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_ERGO},
-	{PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO},
+	{ PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
+	  PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_METRO, 0, 0, BD_METRO },
+	{ PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
+	  PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2, 0, 0, BD_CHAMP2 },
+	{ PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
+	  PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_ERGO, 0, 0, BD_ERGO },
+	{ PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
+	  PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO, 0, 0, BD_ERGO },
+
 	{ }				/* Terminating entry */
 };
 MODULE_DEVICE_TABLE(pci, hysdn_pci_tbl);
@@ -34,128 +39,7 @@
 static char *hysdn_init_revision = "$Revision: 1.6.6.6 $";
 static int cardmax;		/* number of found cards */
 hysdn_card *card_root = NULL;	/* pointer to first card */
-
-/**********************************************/
-/* table assigning PCI-sub ids to board types */
-/* the last entry contains all 0              */
-/**********************************************/
-static struct {
-	unsigned short subid;		/* PCI sub id */
-	unsigned char cardtyp;		/* card type assigned */
-} pci_subid_map[] = {
-
-	{
-		PCI_SUBDEVICE_ID_HYPERCOPE_METRO, BD_METRO
-	},
-	{
-		PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2, BD_CHAMP2
-	},
-	{
-		PCI_SUBDEVICE_ID_HYPERCOPE_ERGO, BD_ERGO
-	},
-	{
-		PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO, BD_ERGO
-	},
-	{
-		0, 0
-	}			/* terminating entry */
-};
-
-
-/*********************************************************************/
-/* search_cards searches for available cards in the pci config data. */
-/* If a card is found, the card structure is allocated and the cards */
-/* ressources are reserved. cardmax is incremented.                  */
-/*********************************************************************/
-static void
-search_cards(void)
-{
-	struct pci_dev *akt_pcidev = NULL;
-	hysdn_card *card, *card_last;
-	int i;
-
-	card_root = NULL;
-	card_last = NULL;
-	while ((akt_pcidev = pci_find_device(PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
-					     akt_pcidev)) != NULL) {
-		if (pci_enable_device(akt_pcidev))
-			continue;
-
-		if (!(card = kzalloc(sizeof(hysdn_card), GFP_KERNEL))) {
-			printk(KERN_ERR "HYSDN: unable to alloc device mem \n");
-			return;
-		}
-		card->myid = cardmax;	/* set own id */
-		card->bus = akt_pcidev->bus->number;
-		card->devfn = akt_pcidev->devfn;	/* slot + function */
-		card->subsysid = akt_pcidev->subsystem_device;
-		card->irq = akt_pcidev->irq;
-		card->iobase = pci_resource_start(akt_pcidev, PCI_REG_PLX_IO_BASE);
-		card->plxbase = pci_resource_start(akt_pcidev, PCI_REG_PLX_MEM_BASE);
-		card->membase = pci_resource_start(akt_pcidev, PCI_REG_MEMORY_BASE);
-		card->brdtype = BD_NONE;	/* unknown */
-		card->debug_flags = DEF_DEB_FLAGS;	/* set default debug */
-		card->faxchans = 0;	/* default no fax channels */
-		card->bchans = 2;	/* and 2 b-channels */
-		for (i = 0; pci_subid_map[i].subid; i++)
-			if (pci_subid_map[i].subid == card->subsysid) {
-				card->brdtype = pci_subid_map[i].cardtyp;
-				break;
-			}
-		if (card->brdtype != BD_NONE) {
-			if (ergo_inithardware(card)) {
-				printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase);
-				kfree(card);
-				continue;
-			}
-		} else {
-			printk(KERN_WARNING "HYSDN: unknown card id 0x%04x\n", card->subsysid);
-			kfree(card);	/* release mem */
-			continue;
-		}
-		cardmax++;
-		card->next = NULL;	/*end of chain */
-		if (card_last)
-			card_last->next = card;		/* pointer to next card */
-		else
-			card_root = card;
-		card_last = card;	/* new chain end */
-	}			/* device found */
-}				/* search_cards */
-
-/************************************************************************************/
-/* free_resources frees the acquired PCI resources and returns the allocated memory */
-/************************************************************************************/
-static void
-free_resources(void)
-{
-	hysdn_card *card;
-
-	while (card_root) {
-		card = card_root;
-		if (card->releasehardware)
-			card->releasehardware(card);	/* free all hardware resources */
-		card_root = card_root->next;	/* remove card from chain */
-		kfree(card);	/* return mem */
-
-	}			/* while card_root */
-}				/* free_resources */
-
-/**************************************************************************/
-/* stop_cards disables (hardware resets) all cards and disables interrupt */
-/**************************************************************************/
-static void
-stop_cards(void)
-{
-	hysdn_card *card;
-
-	card = card_root;	/* first in chain */
-	while (card) {
-		if (card->stopcard)
-			card->stopcard(card);
-		card = card->next;	/* remove card from chain */
-	}			/* while card */
-}				/* stop_cards */
+static hysdn_card *card_last = NULL;	/* pointer to first card */
 
 
 /****************************************************************************/
@@ -191,31 +75,138 @@
 /* and the module is added to the list in /proc/modules, otherwise an error */
 /* is assumed and the module will not be kept in memory.                    */
 /****************************************************************************/
+
+static int __devinit hysdn_pci_init_one(struct pci_dev *akt_pcidev,
+					const struct pci_device_id *ent)
+{
+	hysdn_card *card;
+	int rc;
+
+	rc = pci_enable_device(akt_pcidev);
+	if (rc)
+		return rc;
+
+	if (!(card = kzalloc(sizeof(hysdn_card), GFP_KERNEL))) {
+		printk(KERN_ERR "HYSDN: unable to alloc device mem \n");
+		rc = -ENOMEM;
+		goto err_out;
+	}
+	card->myid = cardmax;	/* set own id */
+	card->bus = akt_pcidev->bus->number;
+	card->devfn = akt_pcidev->devfn;	/* slot + function */
+	card->subsysid = akt_pcidev->subsystem_device;
+	card->irq = akt_pcidev->irq;
+	card->iobase = pci_resource_start(akt_pcidev, PCI_REG_PLX_IO_BASE);
+	card->plxbase = pci_resource_start(akt_pcidev, PCI_REG_PLX_MEM_BASE);
+	card->membase = pci_resource_start(akt_pcidev, PCI_REG_MEMORY_BASE);
+	card->brdtype = BD_NONE;	/* unknown */
+	card->debug_flags = DEF_DEB_FLAGS;	/* set default debug */
+	card->faxchans = 0;	/* default no fax channels */
+	card->bchans = 2;	/* and 2 b-channels */
+	card->brdtype = ent->driver_data;
+
+	if (ergo_inithardware(card)) {
+		printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase);
+		rc = -EBUSY;
+		goto err_out_card;
+	}
+
+	cardmax++;
+	card->next = NULL;	/*end of chain */
+	if (card_last)
+		card_last->next = card;		/* pointer to next card */
+	else
+		card_root = card;
+	card_last = card;	/* new chain end */
+
+	pci_set_drvdata(akt_pcidev, card);
+	return 0;
+
+err_out_card:
+	kfree(card);
+err_out:
+	pci_disable_device(akt_pcidev);
+	return rc;
+}
+
+static void __devexit hysdn_pci_remove_one(struct pci_dev *akt_pcidev)
+{
+	hysdn_card *card = pci_get_drvdata(akt_pcidev);
+
+	pci_set_drvdata(akt_pcidev, NULL);
+
+	if (card->stopcard)
+		card->stopcard(card);
+
+#ifdef CONFIG_HYSDN_CAPI
+	hycapi_capi_release(card);
+#endif
+
+	if (card->releasehardware)
+		card->releasehardware(card);   /* free all hardware resources */
+
+	if (card == card_root) {
+		card_root = card_root->next;
+		if (!card_root)
+			card_last = NULL;
+	} else {
+		hysdn_card *tmp = card_root;
+		while (tmp) {
+			if (tmp->next == card)
+				tmp->next = card->next;
+			card_last = tmp;
+			tmp = tmp->next;
+		}
+	}
+
+	kfree(card);
+	pci_disable_device(akt_pcidev);
+}
+
+static struct pci_driver hysdn_pci_driver = {
+	.name		= "hysdn",
+	.id_table	= hysdn_pci_tbl,
+	.probe		= hysdn_pci_init_one,
+	.remove		= __devexit_p(hysdn_pci_remove_one),
+};
+
+static int hysdn_have_procfs;
+
 static int __init
 hysdn_init(void)
 {
 	char tmp[50];
+	int rc;
 
 	strcpy(tmp, hysdn_init_revision);
 	printk(KERN_NOTICE "HYSDN: module Rev: %s loaded\n", hysdn_getrev(tmp));
 	strcpy(tmp, hysdn_net_revision);
 	printk(KERN_NOTICE "HYSDN: network interface Rev: %s \n", hysdn_getrev(tmp));
-	search_cards();
+
+	rc = pci_register_driver(&hysdn_pci_driver);
+	if (rc)
+		return rc;
+
 	printk(KERN_INFO "HYSDN: %d card(s) found.\n", cardmax);
 
-	if (hysdn_procconf_init()) {
-		free_resources();	/* proc file_sys not created */
-		return (-1);
-	}
+	if (!hysdn_procconf_init())
+		hysdn_have_procfs = 1;
+
 #ifdef CONFIG_HYSDN_CAPI
 	if(cardmax > 0) {
 		if(hycapi_init()) {
 			printk(KERN_ERR "HYCAPI: init failed\n");
-			return(-1);
+
+			if (hysdn_have_procfs)
+				hysdn_procconf_release();
+
+			pci_unregister_driver(&hysdn_pci_driver);
+			return -ESPIPE;
 		}
 	}
 #endif /* CONFIG_HYSDN_CAPI */
-	return (0);		/* no error */
+
+	return 0;		/* no error */
 }				/* init_module */
 
 
@@ -230,20 +221,15 @@
 static void __exit
 hysdn_exit(void)
 {
+	if (hysdn_have_procfs)
+		hysdn_procconf_release();
+
+	pci_unregister_driver(&hysdn_pci_driver);
+
 #ifdef CONFIG_HYSDN_CAPI
-	hysdn_card *card;
-#endif /* CONFIG_HYSDN_CAPI */
-	stop_cards();
-#ifdef CONFIG_HYSDN_CAPI
-	card = card_root;	/* first in chain */
-	while (card) {
-		hycapi_capi_release(card);
-		card = card->next;	/* remove card from chain */
-	}			/* while card */
 	hycapi_cleanup();
 #endif /* CONFIG_HYSDN_CAPI */
-	hysdn_procconf_release();
-	free_resources();
+
 	printk(KERN_NOTICE "HYSDN: module unloaded\n");
 }				/* cleanup_module */
 
diff --git a/drivers/md/md.c b/drivers/md/md.c
index e8f102e..acf1b81 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -3076,8 +3076,7 @@
 	mddev->gendisk = disk;
 	mutex_unlock(&disks_mutex);
 	mddev->kobj.parent = &disk->kobj;
-	mddev->kobj.k_name = NULL;
-	snprintf(mddev->kobj.name, KOBJ_NAME_LEN, "%s", "md");
+	kobject_set_name(&mddev->kobj, "%s", "md");
 	mddev->kobj.ktype = &md_ktype;
 	if (kobject_register(&mddev->kobj))
 		printk(KERN_WARNING "md: cannot register %s/md - name in use\n",
diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c
index 56231d8..18738fa 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.c
+++ b/drivers/media/dvb/dvb-core/dvbdev.c
@@ -103,10 +103,7 @@
 	.open =		dvb_device_open,
 };
 
-static struct cdev dvb_device_cdev = {
-	.kobj   = {.name = "dvb", },
-	.owner  =       THIS_MODULE,
-};
+static struct cdev dvb_device_cdev;
 
 int dvb_generic_open(struct inode *inode, struct file *file)
 {
diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
index 7a78d6b..2ee3c30 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
@@ -905,8 +905,8 @@
 }
 
 
-static int pvr2_sysfs_hotplug(struct device *cd,char **envp,
-			      int numenvp,char *buf,int size)
+static int pvr2_sysfs_hotplug(struct device *d,
+			      struct kobj_uevent_env *env)
 {
 	/* Even though we don't do anything here, we still need this function
 	   because sysfs will still try to call it. */
diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c
index d195fb0..8f77949 100644
--- a/drivers/misc/tifm_core.c
+++ b/drivers/misc/tifm_core.c
@@ -57,16 +57,11 @@
 	return 0;
 }
 
-static int tifm_uevent(struct device *dev, char **envp, int num_envp,
-		       char *buffer, int buffer_size)
+static int tifm_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
-	int i = 0;
-	int length = 0;
 
-	if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
-			   "TIFM_CARD_TYPE=%s",
-			   tifm_media_type_name(sock->type, 1)))
+	if (add_uevent_var(env, "TIFM_CARD_TYPE=%s", tifm_media_type_name(sock->type, 1)))
 		return -ENOMEM;
 
 	return 0;
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 8d6f601..b0c22ca 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -58,12 +58,11 @@
 }
 
 static int
-mmc_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf,
-		int buf_size)
+mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct mmc_card *card = dev_to_mmc_card(dev);
 	const char *type;
-	int i = 0, length = 0;
+	int retval = 0;
 
 	switch (card->type) {
 	case MMC_TYPE_MMC:
@@ -80,20 +79,14 @@
 	}
 
 	if (type) {
-		if (add_uevent_var(envp, num_envp, &i,
-				buf, buf_size, &length,
-				"MMC_TYPE=%s", type))
-			return -ENOMEM;
+		retval = add_uevent_var(env, "MMC_TYPE=%s", type);
+		if (retval)
+			return retval;
 	}
 
-	if (add_uevent_var(envp, num_envp, &i,
-			buf, buf_size, &length,
-			"MMC_NAME=%s", mmc_card_name(card)))
-		return -ENOMEM;
+	retval = add_uevent_var(env, "MMC_NAME=%s", mmc_card_name(card));
 
-	envp[i] = NULL;
-
-	return 0;
+	return retval;
 }
 
 static int mmc_bus_probe(struct device *dev)
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 64fbc97..c65d203 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -143,7 +143,7 @@
 
 	device_del(&host->class_dev);
 
-	led_trigger_unregister(host->led);
+	led_trigger_unregister_simple(host->led);
 
 	spin_lock(&mmc_host_lock);
 	idr_remove(&mmc_host_idr, host->index);
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index d68acce..78ed633 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -2652,10 +2652,10 @@
 		REG_RD(bp, BNX2_HC_COMMAND);
 	}
 
-	if (bp->status_blk->status_tx_quick_consumer_index0 != bp->hw_tx_cons)
+	if (sblk->status_tx_quick_consumer_index0 != bp->hw_tx_cons)
 		bnx2_tx_int(bp);
 
-	if (bp->status_blk->status_rx_quick_consumer_index0 != bp->hw_rx_cons)
+	if (sblk->status_rx_quick_consumer_index0 != bp->hw_rx_cons)
 		work_done += bnx2_rx_int(bp, budget - work_done);
 
 	return work_done;
@@ -2665,6 +2665,7 @@
 {
 	struct bnx2 *bp = container_of(napi, struct bnx2, napi);
 	int work_done = 0;
+	struct status_block *sblk = bp->status_blk;
 
 	while (1) {
 		work_done = bnx2_poll_work(bp, work_done, budget);
@@ -2672,16 +2673,19 @@
 		if (unlikely(work_done >= budget))
 			break;
 
+		/* bp->last_status_idx is used below to tell the hw how
+		 * much work has been processed, so we must read it before
+		 * checking for more work.
+		 */
+		bp->last_status_idx = sblk->status_idx;
+		rmb();
 		if (likely(!bnx2_has_work(bp))) {
-			bp->last_status_idx = bp->status_blk->status_idx;
-			rmb();
-
 			netif_rx_complete(bp->dev, napi);
 			if (likely(bp->flags & USING_MSI_FLAG)) {
 				REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
 				       BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
 				       bp->last_status_idx);
-				return 0;
+				break;
 			}
 			REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
 			       BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index 4ac161e..7d7758f 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -1183,7 +1183,7 @@
 					 pool_count[i], pool_size[i],
 					 pool_active[i]);
 		kobj->parent = &dev->dev.kobj;
-		sprintf(kobj->name, "pool%d", i);
+		kobject_set_name(kobj, "pool%d", i);
 		kobj->ktype = &ktype_veth_pool;
 		kobject_register(kobj);
 	}
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index e795c33..30b1cca 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -3576,7 +3576,7 @@
 	if (sblk->idx[0].tx_consumer != tp->tx_cons) {
 		tg3_tx(tp);
 		if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING))
-			return 0;
+			return work_done;
 	}
 
 	/* run RX thread, within the bounds set by NAPI.
@@ -3593,6 +3593,7 @@
 {
 	struct tg3 *tp = container_of(napi, struct tg3, napi);
 	int work_done = 0;
+	struct tg3_hw_status *sblk = tp->hw_status;
 
 	while (1) {
 		work_done = tg3_poll_work(tp, work_done, budget);
@@ -3603,15 +3604,17 @@
 		if (unlikely(work_done >= budget))
 			break;
 
+		if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) {
+			/* tp->last_tag is used in tg3_restart_ints() below
+			 * to tell the hw how much work has been processed,
+			 * so we must read it before checking for more work.
+			 */
+			tp->last_tag = sblk->status_tag;
+			rmb();
+		} else
+			sblk->status &= ~SD_STATUS_UPDATED;
+
 		if (likely(!tg3_has_work(tp))) {
-			struct tg3_hw_status *sblk = tp->hw_status;
-
-			if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) {
-				tp->last_tag = sblk->status_tag;
-				rmb();
-			} else
-				sblk->status &= ~SD_STATUS_UPDATED;
-
 			netif_rx_complete(tp->dev, napi);
 			tg3_restart_ints(tp);
 			break;
@@ -3621,9 +3624,10 @@
 	return work_done;
 
 tx_recovery:
+	/* work_done is guaranteed to be less than budget. */
 	netif_rx_complete(tp->dev, napi);
 	schedule_work(&tp->reset_task);
-	return 0;
+	return work_done;
 }
 
 static void tg3_irq_quiesce(struct tg3 *tp)
diff --git a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c
index 1c97e7d..2b5352a 100644
--- a/drivers/pci/hotplug.c
+++ b/drivers/pci/hotplug.c
@@ -3,12 +3,9 @@
 #include <linux/module.h>
 #include "pci.h"
 
-int pci_uevent(struct device *dev, char **envp, int num_envp,
-	       char *buffer, int buffer_size)
+int pci_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct pci_dev *pdev;
-	int i = 0;
-	int length = 0;
 
 	if (!dev)
 		return -ENODEV;
@@ -17,37 +14,24 @@
 	if (!pdev)
 		return -ENODEV;
 
-	if (add_uevent_var(envp, num_envp, &i,
-			   buffer, buffer_size, &length,
-			   "PCI_CLASS=%04X", pdev->class))
+	if (add_uevent_var(env, "PCI_CLASS=%04X", pdev->class))
 		return -ENOMEM;
 
-	if (add_uevent_var(envp, num_envp, &i,
-			   buffer, buffer_size, &length,
-			   "PCI_ID=%04X:%04X", pdev->vendor, pdev->device))
+	if (add_uevent_var(env, "PCI_ID=%04X:%04X", pdev->vendor, pdev->device))
 		return -ENOMEM;
 
-	if (add_uevent_var(envp, num_envp, &i,
-			   buffer, buffer_size, &length,
-			   "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor,
+	if (add_uevent_var(env, "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor,
 			   pdev->subsystem_device))
 		return -ENOMEM;
 
-	if (add_uevent_var(envp, num_envp, &i,
-			   buffer, buffer_size, &length,
-			   "PCI_SLOT_NAME=%s", pci_name(pdev)))
+	if (add_uevent_var(env, "PCI_SLOT_NAME=%s", pci_name(pdev)))
 		return -ENOMEM;
 
-	if (add_uevent_var(envp, num_envp, &i,
-			   buffer, buffer_size, &length,
-			   "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x",
+	if (add_uevent_var(env, "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x",
 			   pdev->vendor, pdev->device,
 			   pdev->subsystem_vendor, pdev->subsystem_device,
 			   (u8)(pdev->class >> 16), (u8)(pdev->class >> 8),
 			   (u8)(pdev->class)))
 		return -ENOMEM;
-
-	envp[i] = NULL;
-
 	return 0;
 }
diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
index bd433ef..f0eba53 100644
--- a/drivers/pci/hotplug/pci_hotplug_core.c
+++ b/drivers/pci/hotplug/pci_hotplug_core.c
@@ -694,66 +694,6 @@
 	if ((slot == NULL) || (info == NULL))
 		return -ENODEV;
 
-	/*
-	* check all fields in the info structure, and update timestamps
-	* for the files referring to the fields that have now changed.
-	*/
-	if ((has_power_file(slot) == 0) &&
-	    (slot->info->power_status != info->power_status)) {
-		retval = sysfs_update_file(&slot->kobj,
-					   &hotplug_slot_attr_power.attr);
-		if (retval)
-			return retval;
-	}
-
-	if ((has_attention_file(slot) == 0) &&
-	    (slot->info->attention_status != info->attention_status)) {
-		retval = sysfs_update_file(&slot->kobj,
-					   &hotplug_slot_attr_attention.attr);
-		if (retval)
-			return retval;
-	}
-
-	if ((has_latch_file(slot) == 0) &&
-	    (slot->info->latch_status != info->latch_status)) {
-		retval = sysfs_update_file(&slot->kobj,
-					   &hotplug_slot_attr_latch.attr);
-		if (retval)
-			return retval;
-	}
-
-	if ((has_adapter_file(slot) == 0) &&
-	    (slot->info->adapter_status != info->adapter_status)) {
-		retval = sysfs_update_file(&slot->kobj,
-					   &hotplug_slot_attr_presence.attr);
-		if (retval)
-			return retval;
-	}
-
-	if ((has_address_file(slot) == 0) &&
-	    (slot->info->address != info->address)) {
-		retval = sysfs_update_file(&slot->kobj,
-					   &hotplug_slot_attr_address.attr);
-		if (retval)
-			return retval;
-	}
-
-	if ((has_max_bus_speed_file(slot) == 0) &&
-	    (slot->info->max_bus_speed != info->max_bus_speed)) {
-		retval = sysfs_update_file(&slot->kobj,
-					   &hotplug_slot_attr_max_bus_speed.attr);
-		if (retval)
-			return retval;
-	}
-
-	if ((has_cur_bus_speed_file(slot) == 0) &&
-	    (slot->info->cur_bus_speed != info->cur_bus_speed)) {
-		retval = sysfs_update_file(&slot->kobj,
-					   &hotplug_slot_attr_cur_bus_speed.attr);
-		if (retval)
-			return retval;
-	}
-
 	memcpy (slot->info, info, sizeof (struct hotplug_slot_info));
 
 	return 0;
diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c
index df07606..a080fed 100644
--- a/drivers/pci/hotplug/rpadlpar_sysfs.c
+++ b/drivers/pci/hotplug/rpadlpar_sysfs.c
@@ -129,17 +129,17 @@
 };
 
 struct kset dlpar_io_kset = {
-	.kobj = {.name = DLPAR_KOBJ_NAME,
-		 .ktype = &ktype_dlpar_io,
+	.kobj = {.ktype = &ktype_dlpar_io,
 		 .parent = &pci_hotplug_slots_subsys.kobj},
 	.ktype = &ktype_dlpar_io,
 };
 
 int dlpar_sysfs_init(void)
 {
+	kobject_set_name(&dlpar_io_kset.kobj, DLPAR_KOBJ_NAME);
 	if (kset_register(&dlpar_io_kset)) {
 		printk(KERN_ERR "rpadlpar_io: cannot register kset for %s\n",
-				dlpar_io_kset.kobj.name);
+				kobject_name(&dlpar_io_kset.kobj));
 		return -EINVAL;
 	}
 
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index c43eced..6e2760b 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -531,8 +531,7 @@
 }
 
 #ifndef CONFIG_HOTPLUG
-int pci_uevent(struct device *dev, char **envp, int num_envp,
-	       char *buffer, int buffer_size)
+int pci_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	return -ENODEV;
 }
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 5360d73..6fda33d 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -1,7 +1,6 @@
 /* Functions internal to the PCI core code */
 
-extern int pci_uevent(struct device *dev, char **envp, int num_envp,
-		      char *buffer, int buffer_size);
+extern int pci_uevent(struct device *dev, struct kobj_uevent_env *env);
 extern int pci_create_sysfs_dev_files(struct pci_dev *pdev);
 extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev);
 extern void pci_cleanup_rom(struct pci_dev *dev);
diff --git a/drivers/pci/setup-irq.c b/drivers/pci/setup-irq.c
index 568f187..05ca2ed 100644
--- a/drivers/pci/setup-irq.c
+++ b/drivers/pci/setup-irq.c
@@ -48,7 +48,7 @@
 	dev->irq = irq;
 
 	pr_debug("PCI: fixup irq: (%s) got %d\n",
-		dev->dev.kobj.name, dev->irq);
+		kobject_name(&dev->dev.kobj), 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/pcmcia/cs.c b/drivers/pcmcia/cs.c
index f8b13f0..a0aca46 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -907,18 +907,14 @@
 EXPORT_SYMBOL(pcmcia_insert_card);
 
 
-static int pcmcia_socket_uevent(struct device *dev, char **envp,
-			        int num_envp, char *buffer, int buffer_size)
+static int pcmcia_socket_uevent(struct device *dev,
+				struct kobj_uevent_env *env)
 {
 	struct pcmcia_socket *s = container_of(dev, struct pcmcia_socket, dev);
-	int i = 0, length = 0;
 
-	if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
-			   &length, "SOCKET_NO=%u", s->sock))
+	if (add_uevent_var(env, "SOCKET_NO=%u", s->sock))
 		return -ENOMEM;
 
-	envp[i] = NULL;
-
 	return 0;
 }
 
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index a996071..55baa1f 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -1064,11 +1064,10 @@
 
 #ifdef CONFIG_HOTPLUG
 
-static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp,
-			     char *buffer, int buffer_size)
+static int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct pcmcia_device *p_dev;
-	int i, length = 0;
+	int i;
 	u32 hash[4] = { 0, 0, 0, 0};
 
 	if (!dev)
@@ -1083,23 +1082,13 @@
 		hash[i] = crc32(0, p_dev->prod_id[i], strlen(p_dev->prod_id[i]));
 	}
 
-	i = 0;
-
-	if (add_uevent_var(envp, num_envp, &i,
-			   buffer, buffer_size, &length,
-			   "SOCKET_NO=%u",
-			   p_dev->socket->sock))
+	if (add_uevent_var(env, "SOCKET_NO=%u", p_dev->socket->sock))
 		return -ENOMEM;
 
-	if (add_uevent_var(envp, num_envp, &i,
-			   buffer, buffer_size, &length,
-			   "DEVICE_NO=%02X",
-			   p_dev->device_no))
+	if (add_uevent_var(env, "DEVICE_NO=%02X", p_dev->device_no))
 		return -ENOMEM;
 
-	if (add_uevent_var(envp, num_envp, &i,
-			   buffer, buffer_size, &length,
-			   "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X"
+	if (add_uevent_var(env, "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X"
 			   "pa%08Xpb%08Xpc%08Xpd%08X",
 			   p_dev->has_manf_id ? p_dev->manf_id : 0,
 			   p_dev->has_card_id ? p_dev->card_id : 0,
@@ -1112,15 +1101,12 @@
 			   hash[3]))
 		return -ENOMEM;
 
-	envp[i] = NULL;
-
 	return 0;
 }
 
 #else
 
-static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp,
-			      char *buffer, int buffer_size)
+static int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	return -ENODEV;
 }
diff --git a/drivers/pcmcia/pxa2xx_mainstone.c b/drivers/pcmcia/pxa2xx_mainstone.c
index 383107b..f6722ba 100644
--- a/drivers/pcmcia/pxa2xx_mainstone.c
+++ b/drivers/pcmcia/pxa2xx_mainstone.c
@@ -175,7 +175,6 @@
 	if (!mst_pcmcia_device)
 		return -ENOMEM;
 
-	mst_pcmcia_device->dev.uevent_suppress = 0;
 	mst_pcmcia_device->dev.platform_data = &mst_pcmcia_ops;
 
 	ret = platform_device_add(mst_pcmcia_device);
@@ -195,3 +194,4 @@
 module_exit(mst_pcmcia_exit);
 
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-pcmcia");
diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c
index a2daa3f..d5c33bd 100644
--- a/drivers/pcmcia/pxa2xx_sharpsl.c
+++ b/drivers/pcmcia/pxa2xx_sharpsl.c
@@ -261,7 +261,6 @@
 	if (!sharpsl_pcmcia_device)
 		return -ENOMEM;
 
-	sharpsl_pcmcia_device->dev.uevent_suppress = 0;
 	sharpsl_pcmcia_device->dev.platform_data = &sharpsl_pcmcia_ops;
 	sharpsl_pcmcia_device->dev.parent = platform_scoop_config->devs[0].dev;
 
@@ -284,3 +283,4 @@
 
 MODULE_DESCRIPTION("Sharp SL Series PCMCIA Support");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-pcmcia");
diff --git a/drivers/power/power_supply.h b/drivers/power/power_supply.h
index a9880d4..f38ba48 100644
--- a/drivers/power/power_supply.h
+++ b/drivers/power/power_supply.h
@@ -14,8 +14,7 @@
 
 extern int power_supply_create_attrs(struct power_supply *psy);
 extern void power_supply_remove_attrs(struct power_supply *psy);
-extern int power_supply_uevent(struct device *dev, char **envp, int num_envp,
-			       char *buffer, int buffer_size);
+extern int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env);
 
 #else
 
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index de3155b..249f61b 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -195,11 +195,10 @@
 	return ret;
 }
 
-int power_supply_uevent(struct device *dev, char **envp, int num_envp,
-			char *buffer, int buffer_size)
+int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct power_supply *psy = dev_get_drvdata(dev);
-	int i = 0, length = 0, ret = 0, j;
+	int ret = 0, j;
 	char *prop_buf;
 	char *attrname;
 
@@ -212,8 +211,7 @@
 
 	dev_dbg(dev, "POWER_SUPPLY_NAME=%s\n", psy->name);
 
-	ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
-			     &length, "POWER_SUPPLY_NAME=%s", psy->name);
+	ret = add_uevent_var(env, "POWER_SUPPLY_NAME=%s", psy->name);
 	if (ret)
 		return ret;
 
@@ -243,9 +241,7 @@
 
 		dev_dbg(dev, "Static prop %s=%s\n", attrname, prop_buf);
 
-		ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
-				     &length, "POWER_SUPPLY_%s=%s",
-				     attrname, prop_buf);
+		ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf);
 		kfree(attrname);
 		if (ret)
 			goto out;
@@ -282,14 +278,11 @@
 
 		dev_dbg(dev, "prop %s=%s\n", attrname, prop_buf);
 
-		ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
-				     &length, "POWER_SUPPLY_%s=%s",
-				     attrname, prop_buf);
+		ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf);
 		kfree(attrname);
 		if (ret)
 			goto out;
 	}
-	envp[i] = NULL;
 
 out:
 	free_page((unsigned long)prop_buf);
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index aeda526..d427dae 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -53,6 +53,7 @@
 #include <linux/genhd.h>
 #include <linux/hdreg.h>
 #include <linux/interrupt.h>
+#include <linux/log2.h>
 #include <asm/ccwdev.h>
 #include <linux/workqueue.h>
 #include <asm/debug.h>
@@ -456,7 +457,7 @@
 static inline int
 dasd_check_blocksize(int bsize)
 {
-	if (bsize < 512 || bsize > 4096 || (bsize & (bsize - 1)) != 0)
+	if (bsize < 512 || bsize > 4096 || !is_power_of_2(bsize))
 		return -EMEDIUMTYPE;
 	return 0;
 }
diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c
index 0fbacc8..f231bc2 100644
--- a/drivers/s390/block/xpram.c
+++ b/drivers/s390/block/xpram.c
@@ -230,7 +230,7 @@
 		}
 	}
 	set_bit(BIO_UPTODATE, &bio->bi_flags);
-	bio_end_io(bio, 0);
+	bio_endio(bio, 0);
 	return 0;
 fail:
 	bio_io_error(bio);
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 6000bde..0e1f35c 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -667,6 +667,9 @@
 	struct raw3215_info *raw;
 	int line;
 
+	/* Console is special. */
+	if (raw3215[0] && (cdev->dev.driver_data == raw3215[0]))
+		return 0;
 	raw = kmalloc(sizeof(struct raw3215_info) +
 		      RAW3215_INBUF_SIZE, GFP_KERNEL|GFP_DMA);
 	if (raw == NULL)
diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c
index fd34791..0b04055 100644
--- a/drivers/s390/char/con3270.c
+++ b/drivers/s390/char/con3270.c
@@ -22,6 +22,7 @@
 #include <asm/ebcdic.h>
 
 #include "raw3270.h"
+#include "tty3270.h"
 #include "ctrlchar.h"
 
 #define CON3270_OUTPUT_BUFFER_SIZE 1024
@@ -507,8 +508,6 @@
 	spin_unlock_irqrestore(&cp->view.lock,flags);
 }
 
-extern struct tty_driver *tty3270_driver;
-
 static struct tty_driver *
 con3270_device(struct console *c, int *index)
 {
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c
index fa62e69..25629b9 100644
--- a/drivers/s390/char/sclp.c
+++ b/drivers/s390/char/sclp.c
@@ -93,6 +93,7 @@
 #define SCLP_RETRY_INTERVAL	30
 
 static void sclp_process_queue(void);
+static void __sclp_make_read_req(void);
 static int sclp_init_mask(int calculate);
 static int sclp_init(void);
 
@@ -115,7 +116,6 @@
 	return 0;
 }
 
-static inline void __sclp_make_read_req(void);
 
 static void
 __sclp_queue_read_req(void)
@@ -318,8 +318,7 @@
 }
 
 /* Prepare read event data request. Called while sclp_lock is locked. */
-static inline void
-__sclp_make_read_req(void)
+static void __sclp_make_read_req(void)
 {
 	struct sccb_header *sccb;
 
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c
index 9f244c5..da25f8e 100644
--- a/drivers/s390/char/tape_3590.c
+++ b/drivers/s390/char/tape_3590.c
@@ -708,16 +708,22 @@
 
 	c_info = &TAPE_3590_CRYPT_INFO(device);
 
-	if (sense->masst == MSENSE_UNASSOCIATED) {
+	DBF_EVENT(6, "medium state: %x:%x\n", sense->macst, sense->masst);
+	switch (sense->macst) {
+	case 0x04:
+	case 0x05:
+	case 0x06:
 		tape_med_state_set(device, MS_UNLOADED);
 		TAPE_3590_CRYPT_INFO(device).medium_status = 0;
 		return;
-	}
-	if (sense->masst != MSENSE_ASSOCIATED_MOUNT) {
-		PRINT_ERR("Unknown medium state: %x\n", sense->masst);
+	case 0x08:
+	case 0x09:
+		tape_med_state_set(device, MS_LOADED);
+		break;
+	default:
+		tape_med_state_set(device, MS_UNKNOWN);
 		return;
 	}
-	tape_med_state_set(device, MS_LOADED);
 	c_info->medium_status |= TAPE390_MEDIUM_LOADED_MASK;
 	if (sense->flags & MSENSE_CRYPT_MASK) {
 		PRINT_INFO("Medium is encrypted (%04x)\n", sense->flags);
@@ -835,15 +841,17 @@
 		/* Probably result of halt ssch */
 		return TAPE_IO_PENDING;
 	else if (irb->scsw.dstat == 0x85)
-		/* Device Ready -> check medium state */
-		tape_3590_schedule_work(device, TO_MSEN);
-	else if (irb->scsw.dstat & DEV_STAT_ATTENTION)
+		/* Device Ready */
+		DBF_EVENT(3, "unsol.irq! tape ready: %08x\n", device->cdev_id);
+	else if (irb->scsw.dstat & DEV_STAT_ATTENTION) {
 		tape_3590_schedule_work(device, TO_READ_ATTMSG);
-	else {
+	} else {
 		DBF_EVENT(3, "unsol.irq! dev end: %08x\n", device->cdev_id);
 		PRINT_WARN("Unsolicited IRQ (Device End) caught.\n");
 		tape_dump_sense(device, NULL, irb);
 	}
+	/* check medium state */
+	tape_3590_schedule_work(device, TO_MSEN);
 	return TAPE_IO_SUCCESS;
 }
 
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index bc33068..70b1980a 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -25,8 +25,8 @@
 #include <asm/ebcdic.h>
 #include <asm/uaccess.h>
 
-
 #include "raw3270.h"
+#include "tty3270.h"
 #include "keyboard.h"
 
 #define TTY3270_CHAR_BUF_SIZE 256
@@ -1338,8 +1338,11 @@
 static void
 tty3270_goto_xy(struct tty3270 *tp, int cx, int cy)
 {
-	tp->cx = min_t(int, tp->view.cols - 1, max_t(int, 0, cx));
-	cy = min_t(int, tp->view.rows - 3, max_t(int, 0, cy));
+	int max_cx = max(0, cx);
+	int max_cy = max(0, cy);
+
+	tp->cx = min_t(int, tp->view.cols - 1, max_cx);
+	cy = min_t(int, tp->view.rows - 3, max_cy);
 	if (cy != tp->cy) {
 		tty3270_convert_line(tp, tp->cy);
 		tp->cy = cy;
diff --git a/drivers/s390/char/tty3270.h b/drivers/s390/char/tty3270.h
new file mode 100644
index 0000000..799da57
--- /dev/null
+++ b/drivers/s390/char/tty3270.h
@@ -0,0 +1,16 @@
+/*
+ *  drivers/s390/char/tty3270.h
+ *
+ *    Copyright IBM Corp. 2007
+ *
+ */
+
+#ifndef __DRIVERS_S390_CHAR_TTY3270_H
+#define __DRIVERS_S390_CHAR_TTY3270_H
+
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+
+extern struct tty_driver *tty3270_driver;
+
+#endif /* __DRIVERS_S390_CHAR_TTY3270_H */
diff --git a/drivers/s390/char/vmwatchdog.c b/drivers/s390/char/vmwatchdog.c
index 680b9b5..6f40fac 100644
--- a/drivers/s390/char/vmwatchdog.c
+++ b/drivers/s390/char/vmwatchdog.c
@@ -66,8 +66,8 @@
 		"0:	la	%0,0\n"
 		"1:\n"
 		EX_TABLE(0b,1b)
-		: "=d" (err) : "d"(__func), "d"(__timeout),
-		  "d"(__cmdp), "d"(__cmdl), "0" (-EINVAL) : "1", "cc");
+		: "+d" (err) : "d"(__func), "d"(__timeout),
+		  "d"(__cmdp), "d"(__cmdl) : "1", "cc");
 	return err;
 }
 
diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c
index 3712ede..7073daf 100644
--- a/drivers/s390/char/zcore.c
+++ b/drivers/s390/char/zcore.c
@@ -141,15 +141,16 @@
 
 	if (count == 0)
 		return 0;
-	flags = __raw_local_irq_stnsm(0xf8); /* switch to real mode */
+	flags = __raw_local_irq_stnsm(0xf8UL); /* switch to real mode */
 	asm volatile (
 		"0:	mvcle	%1,%2,0x0\n"
 		"1:	jo	0b\n"
 		"	lhi	%0,0x0\n"
 		"2:\n"
 		EX_TABLE(1b,2b)
-		: "+d" (rc)
-		: "d" (_dest), "d" (_src), "d" (_len1), "d" (_len2)
+		: "+d" (rc), "+d" (_dest), "+d" (_src), "+d" (_len1),
+		  "+d" (_len2), "=m" (*((long*)dest))
+		: "m" (*((long*)src))
 		: "cc", "memory");
 	__raw_local_irq_ssm(flags);
 
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index b0a18f5..5baa517 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -44,8 +44,7 @@
 	return 0;
 }
 static int
-ccwgroup_uevent (struct device *dev, char **envp, int num_envp, char *buffer,
-		  int buffer_size)
+ccwgroup_uevent (struct device *dev, struct kobj_uevent_env *env)
 {
 	/* TODO */
 	return 0;
@@ -152,16 +151,24 @@
 	return 0;
 }
 
-/*
- * try to add a new ccwgroup device for one driver
- * argc and argv[] are a list of bus_id's of devices
- * belonging to the driver.
+/**
+ * ccwgroup_create() - create and register a ccw group device
+ * @root: parent device for the new device
+ * @creator_id: identifier of creating driver
+ * @cdrv: ccw driver of slave devices
+ * @argc: number of slave devices
+ * @argv: bus ids of slave devices
+ *
+ * Create and register a new ccw group device as a child of @root. Slave
+ * devices are obtained from the list of bus ids given in @argv[] and must all
+ * belong to @cdrv.
+ * Returns:
+ *  %0 on success and an error code on failure.
+ * Context:
+ *  non-atomic
  */
-int
-ccwgroup_create(struct device *root,
-		unsigned int creator_id,
-		struct ccw_driver *cdrv,
-		int argc, char *argv[])
+int ccwgroup_create(struct device *root, unsigned int creator_id,
+		    struct ccw_driver *cdrv, int argc, char *argv[])
 {
 	struct ccwgroup_device *gdev;
 	int i;
@@ -390,8 +397,13 @@
 	.remove = ccwgroup_remove,
 };
 
-int
-ccwgroup_driver_register (struct ccwgroup_driver *cdriver)
+/**
+ * ccwgroup_driver_register() - register a ccw group driver
+ * @cdriver: driver to be registered
+ *
+ * This function is mainly a wrapper around driver_register().
+ */
+int ccwgroup_driver_register(struct ccwgroup_driver *cdriver)
 {
 	/* register our new driver with the core */
 	cdriver->driver.bus = &ccwgroup_bus_type;
@@ -406,8 +418,13 @@
 	return 1;
 }
 
-void
-ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver)
+/**
+ * ccwgroup_driver_unregister() - deregister a ccw group driver
+ * @cdriver: driver to be deregistered
+ *
+ * This function is mainly a wrapper around driver_unregister().
+ */
+void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver)
 {
 	struct device *dev;
 
@@ -427,8 +444,16 @@
 	driver_unregister(&cdriver->driver);
 }
 
-int
-ccwgroup_probe_ccwdev(struct ccw_device *cdev)
+/**
+ * ccwgroup_probe_ccwdev() - probe function for slave devices
+ * @cdev: ccw device to be probed
+ *
+ * This is a dummy probe function for ccw devices that are slave devices in
+ * a ccw group device.
+ * Returns:
+ *  always %0
+ */
+int ccwgroup_probe_ccwdev(struct ccw_device *cdev)
 {
 	return 0;
 }
@@ -452,8 +477,15 @@
 	return NULL;
 }
 
-void
-ccwgroup_remove_ccwdev(struct ccw_device *cdev)
+/**
+ * ccwgroup_remove_ccwdev() - remove function for slave devices
+ * @cdev: ccw device to be removed
+ *
+ * This is a remove function for ccw devices that are slave devices in a ccw
+ * group device. It sets the ccw device offline and also deregisters the
+ * embedding ccw group device.
+ */
+void ccwgroup_remove_ccwdev(struct ccw_device *cdev)
 {
 	struct ccwgroup_device *gdev;
 
diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c
index 920dd71..42c1f46 100644
--- a/drivers/s390/cio/chp.c
+++ b/drivers/s390/cio/chp.c
@@ -14,7 +14,7 @@
 #include <linux/jiffies.h>
 #include <linux/wait.h>
 #include <linux/mutex.h>
-#include <asm/errno.h>
+#include <linux/errno.h>
 #include <asm/chpid.h>
 #include <asm/sclp.h>
 
@@ -55,7 +55,7 @@
 /* Return channel_path struct for given chpid. */
 static inline struct channel_path *chpid_to_chp(struct chp_id chpid)
 {
-	return css[chpid.cssid]->chps[chpid.id];
+	return channel_subsystems[chpid.cssid]->chps[chpid.id];
 }
 
 /* Set vary state for given chpid. */
@@ -86,7 +86,7 @@
 
 	opm = 0;
 	chp_id_init(&chpid);
-	for (i=0; i < 8; i++) {
+	for (i = 0; i < 8; i++) {
 		opm <<= 1;
 		chpid.id = sch->schib.pmcw.chpid[i];
 		if (chp_get_status(chpid) != 0)
@@ -118,7 +118,7 @@
 
 	sprintf(dbf_text, on?"varyon%x.%02x":"varyoff%x.%02x", chpid.cssid,
 		chpid.id);
-	CIO_TRACE_EVENT( 2, dbf_text);
+	CIO_TRACE_EVENT(2, dbf_text);
 
 	status = chp_get_status(chpid);
 	if (!on && !status) {
@@ -140,9 +140,11 @@
 					  char *buf, loff_t off, size_t count)
 {
 	struct channel_path *chp;
+	struct device *device;
 	unsigned int size;
 
-	chp = to_channelpath(container_of(kobj, struct device, kobj));
+	device = container_of(kobj, struct device, kobj);
+	chp = to_channelpath(device);
 	if (!chp->cmg_chars)
 		return 0;
 
@@ -193,9 +195,11 @@
 {
 	struct channel_path *chp;
 	struct channel_subsystem *css;
+	struct device *device;
 	unsigned int size;
 
-	chp = to_channelpath(container_of(kobj, struct device, kobj));
+	device = container_of(kobj, struct device, kobj);
+	chp = to_channelpath(device);
 	css = to_css(chp->dev.parent);
 
 	size = sizeof(struct cmg_entry);
@@ -353,7 +357,7 @@
 
 static DEVICE_ATTR(shared, 0444, chp_shared_show, NULL);
 
-static struct attribute * chp_attrs[] = {
+static struct attribute *chp_attrs[] = {
 	&dev_attr_status.attr,
 	&dev_attr_configure.attr,
 	&dev_attr_type.attr,
@@ -395,7 +399,7 @@
 	/* fill in status, etc. */
 	chp->chpid = chpid;
 	chp->state = 1;
-	chp->dev.parent = &css[chpid.cssid]->device;
+	chp->dev.parent = &channel_subsystems[chpid.cssid]->device;
 	chp->dev.release = chp_release;
 	snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp%x.%02x", chpid.cssid,
 		 chpid.id);
@@ -430,18 +434,18 @@
 		device_unregister(&chp->dev);
 		goto out_free;
 	}
-	mutex_lock(&css[chpid.cssid]->mutex);
-	if (css[chpid.cssid]->cm_enabled) {
+	mutex_lock(&channel_subsystems[chpid.cssid]->mutex);
+	if (channel_subsystems[chpid.cssid]->cm_enabled) {
 		ret = chp_add_cmg_attr(chp);
 		if (ret) {
 			sysfs_remove_group(&chp->dev.kobj, &chp_attr_group);
 			device_unregister(&chp->dev);
-			mutex_unlock(&css[chpid.cssid]->mutex);
+			mutex_unlock(&channel_subsystems[chpid.cssid]->mutex);
 			goto out_free;
 		}
 	}
-	css[chpid.cssid]->chps[chpid.id] = chp;
-	mutex_unlock(&css[chpid.cssid]->mutex);
+	channel_subsystems[chpid.cssid]->chps[chpid.id] = chp;
+	mutex_unlock(&channel_subsystems[chpid.cssid]->mutex);
 	return ret;
 out_free:
 	kfree(chp);
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index f2708d6..4690534 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -619,6 +619,11 @@
 	sch->schib.pmcw.ena = 0;
 	if ((sch->lpm & (sch->lpm - 1)) != 0)
 		sch->schib.pmcw.mp = 1;	/* multipath mode */
+	/* clean up possible residual cmf stuff */
+	sch->schib.pmcw.mme = 0;
+	sch->schib.pmcw.mbfc = 0;
+	sch->schib.pmcw.mbi = 0;
+	sch->schib.mba = 0;
 	return 0;
 out:
 	if (!cio_is_console(schid))
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c
index 34a7969..b960f66 100644
--- a/drivers/s390/cio/cmf.c
+++ b/drivers/s390/cio/cmf.c
@@ -45,7 +45,8 @@
 #include "ioasm.h"
 #include "chsc.h"
 
-/* parameter to enable cmf during boot, possible uses are:
+/*
+ * parameter to enable cmf during boot, possible uses are:
  *  "s390cmf" -- enable cmf and allocate 2 MB of ram so measuring can be
  *               used on any subchannel
  *  "s390cmf=<num>" -- enable cmf and allocate enough memory to measure
@@ -73,18 +74,20 @@
  * enum cmb_format - types of supported measurement block formats
  *
  * @CMF_BASIC:      traditional channel measurement blocks supported
- * 		    by all machines that we run on
+ *		    by all machines that we run on
  * @CMF_EXTENDED:   improved format that was introduced with the z990
- * 		    machine
- * @CMF_AUTODETECT: default: use extended format when running on a z990
- *                  or later machine, otherwise fall back to basic format
- **/
+ *		    machine
+ * @CMF_AUTODETECT: default: use extended format when running on a machine
+ *		    supporting extended format, otherwise fall back to
+ *		    basic format
+ */
 enum cmb_format {
 	CMF_BASIC,
 	CMF_EXTENDED,
 	CMF_AUTODETECT = -1,
 };
-/**
+
+/*
  * format - actual format for all measurement blocks
  *
  * The format module parameter can be set to a value of 0 (zero)
@@ -105,20 +108,21 @@
  *		either with the help of a special pool or with kmalloc
  * @free:	free memory allocated with @alloc
  * @set:	enable or disable measurement
+ * @read:	read a measurement entry at an index
  * @readall:	read a measurement block in a common format
  * @reset:	clear the data in the associated measurement block and
  *		reset its time stamp
  * @align:	align an allocated block so that the hardware can use it
  */
 struct cmb_operations {
-	int (*alloc)  (struct ccw_device*);
-	void(*free)   (struct ccw_device*);
-	int (*set)    (struct ccw_device*, u32);
-	u64 (*read)   (struct ccw_device*, int);
-	int (*readall)(struct ccw_device*, struct cmbdata *);
-	void (*reset) (struct ccw_device*);
-	void * (*align) (void *);
-
+	int  (*alloc)  (struct ccw_device *);
+	void (*free)   (struct ccw_device *);
+	int  (*set)    (struct ccw_device *, u32);
+	u64  (*read)   (struct ccw_device *, int);
+	int  (*readall)(struct ccw_device *, struct cmbdata *);
+	void (*reset)  (struct ccw_device *);
+	void *(*align) (void *);
+/* private: */
 	struct attribute_group *attr_group;
 };
 static struct cmb_operations *cmbops;
@@ -130,9 +134,11 @@
 	unsigned long long last_update;  /* when last_block was updated */
 };
 
-/* our user interface is designed in terms of nanoseconds,
+/*
+ * Our user interface is designed in terms of nanoseconds,
  * while the hardware measures total times in its own
- * unit.*/
+ * unit.
+ */
 static inline u64 time_to_nsec(u32 value)
 {
 	return ((u64)value) * 128000ull;
@@ -159,12 +165,13 @@
 	return ret;
 }
 
-/* activate or deactivate the channel monitor. When area is NULL,
+/*
+ * Activate or deactivate the channel monitor. When area is NULL,
  * the monitor is deactivated. The channel monitor needs to
  * be active in order to measure subchannels, which also need
- * to be enabled. */
-static inline void
-cmf_activate(void *area, unsigned int onoff)
+ * to be enabled.
+ */
+static inline void cmf_activate(void *area, unsigned int onoff)
 {
 	register void * __gpr2 asm("2");
 	register long __gpr1 asm("1");
@@ -175,8 +182,8 @@
 	asm("schm" : : "d" (__gpr2), "d" (__gpr1) );
 }
 
-static int
-set_schib(struct ccw_device *cdev, u32 mme, int mbfc, unsigned long address)
+static int set_schib(struct ccw_device *cdev, u32 mme, int mbfc,
+		     unsigned long address)
 {
 	int ret;
 	int retry;
@@ -466,6 +473,7 @@
  *
  * @mem:	pointer to CMBs (only in basic measurement mode)
  * @list:	contains a linked list of all subchannels
+ * @num_channels: number of channels to be measured
  * @lock:	protect concurrent access to @mem and @list
  */
 struct cmb_area {
@@ -481,28 +489,36 @@
 	.num_channels  = 1024,
 };
 
-
 /* ****** old style CMB handling ********/
 
-/** int maxchannels
- *
+/*
  * Basic channel measurement blocks are allocated in one contiguous
  * block of memory, which can not be moved as long as any channel
  * is active. Therefore, a maximum number of subchannels needs to
  * be defined somewhere. This is a module parameter, defaulting to
  * a resonable value of 1024, or 32 kb of memory.
  * Current kernels don't allow kmalloc with more than 128kb, so the
- * maximum is 4096
+ * maximum is 4096.
  */
 
 module_param_named(maxchannels, cmb_area.num_channels, uint, 0444);
 
 /**
  * struct cmb - basic channel measurement block
+ * @ssch_rsch_count: number of ssch and rsch
+ * @sample_count: number of samples
+ * @device_connect_time: time of device connect
+ * @function_pending_time: time of function pending
+ * @device_disconnect_time: time of device disconnect
+ * @control_unit_queuing_time: time of control unit queuing
+ * @device_active_only_time: time of device active only
+ * @reserved: unused in basic measurement mode
  *
- * cmb as used by the hardware the fields are described in z/Architecture
- * Principles of Operation, chapter 17.
- * The area to be a contiguous array and may not be reallocated or freed.
+ * The measurement block as used by the hardware. The fields are described
+ * further in z/Architecture Principles of Operation, chapter 17.
+ *
+ * The cmb area made up from these blocks must be a contiguous array and may
+ * not be reallocated or freed.
  * Only one cmb area can be present in the system.
  */
 struct cmb {
@@ -516,8 +532,9 @@
 	u32 reserved[2];
 };
 
-/* insert a single device into the cmb_area list
- * called with cmb_area.lock held from alloc_cmb
+/*
+ * Insert a single device into the cmb_area list.
+ * Called with cmb_area.lock held from alloc_cmb.
  */
 static int alloc_cmb_single(struct ccw_device *cdev,
 			    struct cmb_data *cmb_data)
@@ -532,9 +549,11 @@
 		goto out;
 	}
 
-	/* find first unused cmb in cmb_area.mem.
-	 * this is a little tricky: cmb_area.list
-	 * remains sorted by ->cmb->hw_data pointers */
+	/*
+	 * Find first unused cmb in cmb_area.mem.
+	 * This is a little tricky: cmb_area.list
+	 * remains sorted by ->cmb->hw_data pointers.
+	 */
 	cmb = cmb_area.mem;
 	list_for_each_entry(node, &cmb_area.list, cmb_list) {
 		struct cmb_data *data;
@@ -558,8 +577,7 @@
 	return ret;
 }
 
-static int
-alloc_cmb (struct ccw_device *cdev)
+static int alloc_cmb(struct ccw_device *cdev)
 {
 	int ret;
 	struct cmb *mem;
@@ -670,7 +688,7 @@
 	return set_schib_wait(cdev, mme, 0, offset);
 }
 
-static u64 read_cmb (struct ccw_device *cdev, int index)
+static u64 read_cmb(struct ccw_device *cdev, int index)
 {
 	struct cmb *cmb;
 	u32 val;
@@ -720,7 +738,7 @@
 	return ret;
 }
 
-static int readall_cmb (struct ccw_device *cdev, struct cmbdata *data)
+static int readall_cmb(struct ccw_device *cdev, struct cmbdata *data)
 {
 	struct cmb *cmb;
 	struct cmb_data *cmb_data;
@@ -793,14 +811,25 @@
 	.align	    = align_cmb,
 	.attr_group = &cmf_attr_group,
 };
-
+
 /* ******** extended cmb handling ********/
 
 /**
  * struct cmbe - extended channel measurement block
+ * @ssch_rsch_count: number of ssch and rsch
+ * @sample_count: number of samples
+ * @device_connect_time: time of device connect
+ * @function_pending_time: time of function pending
+ * @device_disconnect_time: time of device disconnect
+ * @control_unit_queuing_time: time of control unit queuing
+ * @device_active_only_time: time of device active only
+ * @device_busy_time: time of device busy
+ * @initial_command_response_time: initial command response time
+ * @reserved: unused
  *
- * cmb as used by the hardware, may be in any 64 bit physical location,
- * the fields are described in z/Architecture Principles of Operation,
+ * The measurement block as used by the hardware. May be in any 64 bit physical
+ * location.
+ * The fields are described further in z/Architecture Principles of Operation,
  * third edition, chapter 17.
  */
 struct cmbe {
@@ -816,10 +845,12 @@
 	u32 reserved[7];
 };
 
-/* kmalloc only guarantees 8 byte alignment, but we need cmbe
+/*
+ * kmalloc only guarantees 8 byte alignment, but we need cmbe
  * pointers to be naturally aligned. Make sure to allocate
- * enough space for two cmbes */
-static inline struct cmbe* cmbe_align(struct cmbe *c)
+ * enough space for two cmbes.
+ */
+static inline struct cmbe *cmbe_align(struct cmbe *c)
 {
 	unsigned long addr;
 	addr = ((unsigned long)c + sizeof (struct cmbe) - sizeof(long)) &
@@ -827,7 +858,7 @@
 	return (struct cmbe*)addr;
 }
 
-static int alloc_cmbe (struct ccw_device *cdev)
+static int alloc_cmbe(struct ccw_device *cdev)
 {
 	struct cmbe *cmbe;
 	struct cmb_data *cmb_data;
@@ -873,7 +904,7 @@
 	return ret;
 }
 
-static void free_cmbe (struct ccw_device *cdev)
+static void free_cmbe(struct ccw_device *cdev)
 {
 	struct cmb_data *cmb_data;
 
@@ -912,7 +943,7 @@
 }
 
 
-static u64 read_cmbe (struct ccw_device *cdev, int index)
+static u64 read_cmbe(struct ccw_device *cdev, int index)
 {
 	struct cmbe *cmb;
 	struct cmb_data *cmb_data;
@@ -970,7 +1001,7 @@
 	return ret;
 }
 
-static int readall_cmbe (struct ccw_device *cdev, struct cmbdata *data)
+static int readall_cmbe(struct ccw_device *cdev, struct cmbdata *data)
 {
 	struct cmbe *cmb;
 	struct cmb_data *cmb_data;
@@ -1047,17 +1078,16 @@
 	.align	    = align_cmbe,
 	.attr_group = &cmf_attr_group_ext,
 };
-
 
-static ssize_t
-cmb_show_attr(struct device *dev, char *buf, enum cmb_index idx)
+static ssize_t cmb_show_attr(struct device *dev, char *buf, enum cmb_index idx)
 {
 	return sprintf(buf, "%lld\n",
 		(unsigned long long) cmf_read(to_ccwdev(dev), idx));
 }
 
-static ssize_t
-cmb_show_avg_sample_interval(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t cmb_show_avg_sample_interval(struct device *dev,
+					    struct device_attribute *attr,
+					    char *buf)
 {
 	struct ccw_device *cdev;
 	long interval;
@@ -1079,8 +1109,9 @@
 	return sprintf(buf, "%ld\n", interval);
 }
 
-static ssize_t
-cmb_show_avg_utilization(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t cmb_show_avg_utilization(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
 {
 	struct cmbdata data;
 	u64 utilization;
@@ -1112,14 +1143,16 @@
 }
 
 #define cmf_attr(name) \
-static ssize_t show_ ## name (struct device * dev, struct device_attribute *attr, char * buf) \
-{ return cmb_show_attr((dev), buf, cmb_ ## name); } \
-static DEVICE_ATTR(name, 0444, show_ ## name, NULL);
+static ssize_t show_##name(struct device *dev, \
+			   struct device_attribute *attr, char *buf)	\
+{ return cmb_show_attr((dev), buf, cmb_##name); } \
+static DEVICE_ATTR(name, 0444, show_##name, NULL);
 
 #define cmf_attr_avg(name) \
-static ssize_t show_avg_ ## name (struct device * dev, struct device_attribute *attr, char * buf) \
-{ return cmb_show_attr((dev), buf, cmb_ ## name); } \
-static DEVICE_ATTR(avg_ ## name, 0444, show_avg_ ## name, NULL);
+static ssize_t show_avg_##name(struct device *dev, \
+			       struct device_attribute *attr, char *buf) \
+{ return cmb_show_attr((dev), buf, cmb_##name); } \
+static DEVICE_ATTR(avg_##name, 0444, show_avg_##name, NULL);
 
 cmf_attr(ssch_rsch_count);
 cmf_attr(sample_count);
@@ -1131,7 +1164,8 @@
 cmf_attr_avg(device_busy_time);
 cmf_attr_avg(initial_command_response_time);
 
-static DEVICE_ATTR(avg_sample_interval, 0444, cmb_show_avg_sample_interval, NULL);
+static DEVICE_ATTR(avg_sample_interval, 0444, cmb_show_avg_sample_interval,
+		   NULL);
 static DEVICE_ATTR(avg_utilization, 0444, cmb_show_avg_utilization, NULL);
 
 static struct attribute *cmf_attributes[] = {
@@ -1172,12 +1206,16 @@
 	.attrs = cmf_attributes_ext,
 };
 
-static ssize_t cmb_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t cmb_enable_show(struct device *dev,
+			       struct device_attribute *attr,
+			       char *buf)
 {
 	return sprintf(buf, "%d\n", to_ccwdev(dev)->private->cmb ? 1 : 0);
 }
 
-static ssize_t cmb_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t c)
+static ssize_t cmb_enable_store(struct device *dev,
+				struct device_attribute *attr, const char *buf,
+				size_t c)
 {
 	struct ccw_device *cdev;
 	int ret;
@@ -1202,9 +1240,16 @@
 
 DEVICE_ATTR(cmb_enable, 0644, cmb_enable_show, cmb_enable_store);
 
-/* enable_cmf/disable_cmf: module interface for cmf (de)activation */
-int
-enable_cmf(struct ccw_device *cdev)
+/**
+ * enable_cmf() - switch on the channel measurement for a specific device
+ *  @cdev:	The ccw device to be enabled
+ *
+ *  Returns %0 for success or a negative error value.
+ *
+ *  Context:
+ *    non-atomic
+ */
+int enable_cmf(struct ccw_device *cdev)
 {
 	int ret;
 
@@ -1225,8 +1270,16 @@
 	return ret;
 }
 
-int
-disable_cmf(struct ccw_device *cdev)
+/**
+ * disable_cmf() - switch off the channel measurement for a specific device
+ *  @cdev:	The ccw device to be disabled
+ *
+ *  Returns %0 for success or a negative error value.
+ *
+ *  Context:
+ *    non-atomic
+ */
+int disable_cmf(struct ccw_device *cdev)
 {
 	int ret;
 
@@ -1238,14 +1291,32 @@
 	return ret;
 }
 
-u64
-cmf_read(struct ccw_device *cdev, int index)
+/**
+ * cmf_read() - read one value from the current channel measurement block
+ * @cdev:	the channel to be read
+ * @index:	the index of the value to be read
+ *
+ * Returns the value read or %0 if the value cannot be read.
+ *
+ *  Context:
+ *    any
+ */
+u64 cmf_read(struct ccw_device *cdev, int index)
 {
 	return cmbops->read(cdev, index);
 }
 
-int
-cmf_readall(struct ccw_device *cdev, struct cmbdata *data)
+/**
+ * cmf_readall() - read the current channel measurement block
+ * @cdev:	the channel to be read
+ * @data:	a pointer to a data block that will be filled
+ *
+ * Returns %0 on success, a negative error value otherwise.
+ *
+ *  Context:
+ *    any
+ */
+int cmf_readall(struct ccw_device *cdev, struct cmbdata *data)
 {
 	return cmbops->readall(cdev, data);
 }
@@ -1257,15 +1328,16 @@
 	return cmbops->set(cdev, 2);
 }
 
-static int __init
-init_cmf(void)
+static int __init init_cmf(void)
 {
 	char *format_string;
 	char *detect_string = "parameter";
 
-	/* We cannot really autoprobe this. If the user did not give a parameter,
-	   see if we are running on z990 or up, otherwise fall back to basic mode. */
-
+	/*
+	 * If the user did not give a parameter, see if we are running on a
+	 * machine supporting extended measurement blocks, otherwise fall back
+	 * to basic mode.
+	 */
 	if (format == CMF_AUTODETECT) {
 		if (!css_characteristics_avail ||
 		    !css_general_characteristics.ext_mb) {
@@ -1284,7 +1356,7 @@
 		cmbops = &cmbops_basic;
 		break;
 	case CMF_EXTENDED:
- 		format_string = "extended";
+		format_string = "extended";
 		cmbops = &cmbops_extended;
 		break;
 	default:
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 5635e65..5d83dd4 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -13,6 +13,7 @@
 #include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/list.h>
+#include <linux/reboot.h>
 
 #include "css.h"
 #include "cio.h"
@@ -27,7 +28,7 @@
 static int need_reprobe = 0;
 static int max_ssid = 0;
 
-struct channel_subsystem *css[__MAX_CSSID + 1];
+struct channel_subsystem *channel_subsystems[__MAX_CSSID + 1];
 
 int css_characteristics_avail = 0;
 
@@ -177,7 +178,7 @@
 	int ret;
 
 	/* Initialize the subchannel structure */
-	sch->dev.parent = &css[0]->device;
+	sch->dev.parent = &channel_subsystems[0]->device;
 	sch->dev.bus = &css_bus_type;
 	sch->dev.release = &css_subchannel_release;
 	sch->dev.groups = subch_attr_groups;
@@ -606,30 +607,55 @@
 {
 	u32 tod_high;
 	int ret;
+	struct channel_subsystem *css;
 
-	memset(css[nr], 0, sizeof(struct channel_subsystem));
-	css[nr]->pseudo_subchannel =
-		kzalloc(sizeof(*css[nr]->pseudo_subchannel), GFP_KERNEL);
-	if (!css[nr]->pseudo_subchannel)
+	css = channel_subsystems[nr];
+	memset(css, 0, sizeof(struct channel_subsystem));
+	css->pseudo_subchannel =
+		kzalloc(sizeof(*css->pseudo_subchannel), GFP_KERNEL);
+	if (!css->pseudo_subchannel)
 		return -ENOMEM;
-	css[nr]->pseudo_subchannel->dev.parent = &css[nr]->device;
-	css[nr]->pseudo_subchannel->dev.release = css_subchannel_release;
-	sprintf(css[nr]->pseudo_subchannel->dev.bus_id, "defunct");
-	ret = cio_create_sch_lock(css[nr]->pseudo_subchannel);
+	css->pseudo_subchannel->dev.parent = &css->device;
+	css->pseudo_subchannel->dev.release = css_subchannel_release;
+	sprintf(css->pseudo_subchannel->dev.bus_id, "defunct");
+	ret = cio_create_sch_lock(css->pseudo_subchannel);
 	if (ret) {
-		kfree(css[nr]->pseudo_subchannel);
+		kfree(css->pseudo_subchannel);
 		return ret;
 	}
-	mutex_init(&css[nr]->mutex);
-	css[nr]->valid = 1;
-	css[nr]->cssid = nr;
-	sprintf(css[nr]->device.bus_id, "css%x", nr);
-	css[nr]->device.release = channel_subsystem_release;
+	mutex_init(&css->mutex);
+	css->valid = 1;
+	css->cssid = nr;
+	sprintf(css->device.bus_id, "css%x", nr);
+	css->device.release = channel_subsystem_release;
 	tod_high = (u32) (get_clock() >> 32);
-	css_generate_pgid(css[nr], tod_high);
+	css_generate_pgid(css, tod_high);
 	return 0;
 }
 
+static int css_reboot_event(struct notifier_block *this,
+			    unsigned long event,
+			    void *ptr)
+{
+	int ret, i;
+
+	ret = NOTIFY_DONE;
+	for (i = 0; i <= __MAX_CSSID; i++) {
+		struct channel_subsystem *css;
+
+		css = channel_subsystems[i];
+		if (css->cm_enabled)
+			if (chsc_secm(css, 0))
+				ret = NOTIFY_BAD;
+	}
+
+	return ret;
+}
+
+static struct notifier_block css_reboot_notifier = {
+	.notifier_call = css_reboot_event,
+};
+
 /*
  * Now that the driver core is running, we can setup our channel subsystem.
  * The struct subchannel's are created during probing (except for the
@@ -670,51 +696,63 @@
 	}
 	/* Setup css structure. */
 	for (i = 0; i <= __MAX_CSSID; i++) {
-		css[i] = kmalloc(sizeof(struct channel_subsystem), GFP_KERNEL);
-		if (!css[i]) {
+		struct channel_subsystem *css;
+
+		css = kmalloc(sizeof(struct channel_subsystem), GFP_KERNEL);
+		if (!css) {
 			ret = -ENOMEM;
 			goto out_unregister;
 		}
+		channel_subsystems[i] = css;
 		ret = setup_css(i);
 		if (ret)
 			goto out_free;
-		ret = device_register(&css[i]->device);
+		ret = device_register(&css->device);
 		if (ret)
 			goto out_free_all;
 		if (css_characteristics_avail &&
 		    css_chsc_characteristics.secm) {
-			ret = device_create_file(&css[i]->device,
+			ret = device_create_file(&css->device,
 						 &dev_attr_cm_enable);
 			if (ret)
 				goto out_device;
 		}
-		ret = device_register(&css[i]->pseudo_subchannel->dev);
+		ret = device_register(&css->pseudo_subchannel->dev);
 		if (ret)
 			goto out_file;
 	}
+	ret = register_reboot_notifier(&css_reboot_notifier);
+	if (ret)
+		goto out_pseudo;
 	css_init_done = 1;
 
 	ctl_set_bit(6, 28);
 
 	for_each_subchannel(__init_channel_subsystem, NULL);
 	return 0;
+out_pseudo:
+	device_unregister(&channel_subsystems[i]->pseudo_subchannel->dev);
 out_file:
-	device_remove_file(&css[i]->device, &dev_attr_cm_enable);
+	device_remove_file(&channel_subsystems[i]->device,
+			   &dev_attr_cm_enable);
 out_device:
-	device_unregister(&css[i]->device);
+	device_unregister(&channel_subsystems[i]->device);
 out_free_all:
-	kfree(css[i]->pseudo_subchannel->lock);
-	kfree(css[i]->pseudo_subchannel);
+	kfree(channel_subsystems[i]->pseudo_subchannel->lock);
+	kfree(channel_subsystems[i]->pseudo_subchannel);
 out_free:
-	kfree(css[i]);
+	kfree(channel_subsystems[i]);
 out_unregister:
 	while (i > 0) {
+		struct channel_subsystem *css;
+
 		i--;
-		device_unregister(&css[i]->pseudo_subchannel->dev);
+		css = channel_subsystems[i];
+		device_unregister(&css->pseudo_subchannel->dev);
 		if (css_characteristics_avail && css_chsc_characteristics.secm)
-			device_remove_file(&css[i]->device,
+			device_remove_file(&css->device,
 					   &dev_attr_cm_enable);
-		device_unregister(&css[i]->device);
+		device_unregister(&css->device);
 	}
 out_bus:
 	bus_unregister(&css_bus_type);
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
index 5d65e83..81215ef 100644
--- a/drivers/s390/cio/css.h
+++ b/drivers/s390/cio/css.h
@@ -167,7 +167,7 @@
 #define to_css(dev) container_of(dev, struct channel_subsystem, device)
 
 extern struct bus_type css_bus_type;
-extern struct channel_subsystem *css[];
+extern struct channel_subsystem *channel_subsystems[];
 
 /* Some helper functions for disconnected state. */
 int device_is_disconnected(struct subchannel *);
@@ -191,6 +191,5 @@
 
 extern struct workqueue_struct *slow_path_wq;
 
-int subchannel_add_files (struct device *);
 extern struct attribute_group *subch_attr_groups[];
 #endif
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index e44d92e..7ee57f0 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -21,6 +21,7 @@
 #include <asm/ccwdev.h>
 #include <asm/cio.h>
 #include <asm/param.h>		/* HZ */
+#include <asm/cmb.h>
 
 #include "cio.h"
 #include "cio_debug.h"
@@ -78,49 +79,38 @@
 
 /* Set up environment variables for ccw device uevent. Return 0 on success,
  * non-zero otherwise. */
-static int ccw_uevent(struct device *dev, char **envp, int num_envp,
-		      char *buffer, int buffer_size)
+static int ccw_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct ccw_device *cdev = to_ccwdev(dev);
 	struct ccw_device_id *id = &(cdev->id);
-	int i = 0;
-	int len = 0;
 	int ret;
 	char modalias_buf[30];
 
 	/* CU_TYPE= */
-	ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
-			     "CU_TYPE=%04X", id->cu_type);
+	ret = add_uevent_var(env, "CU_TYPE=%04X", id->cu_type);
 	if (ret)
 		return ret;
 
 	/* CU_MODEL= */
-	ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
-			     "CU_MODEL=%02X", id->cu_model);
+	ret = add_uevent_var(env, "CU_MODEL=%02X", id->cu_model);
 	if (ret)
 		return ret;
 
 	/* The next two can be zero, that's ok for us */
 	/* DEV_TYPE= */
-	ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
-			     "DEV_TYPE=%04X", id->dev_type);
+	ret = add_uevent_var(env, "DEV_TYPE=%04X", id->dev_type);
 	if (ret)
 		return ret;
 
 	/* DEV_MODEL= */
-	ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
-			     "DEV_MODEL=%02X", id->dev_model);
+	ret = add_uevent_var(env, "DEV_MODEL=%02X", id->dev_model);
 	if (ret)
 		return ret;
 
 	/* MODALIAS=  */
 	snprint_alias(modalias_buf, sizeof(modalias_buf), id, "");
-	ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
-			     "MODALIAS=%s", modalias_buf);
-	if (ret)
-		return ret;
-	envp[i] = NULL;
-	return 0;
+	ret = add_uevent_var(env, "MODALIAS=%s", modalias_buf);
+	return ret;
 }
 
 struct bus_type ccw_bus_type;
@@ -357,8 +347,18 @@
 			      cdev->private->dev_id.devno);
 }
 
-int
-ccw_device_set_offline(struct ccw_device *cdev)
+/**
+ * ccw_device_set_offline() - disable a ccw device for I/O
+ * @cdev: target ccw device
+ *
+ * This function calls the driver's set_offline() function for @cdev, if
+ * given, and then disables @cdev.
+ * Returns:
+ *   %0 on success and a negative error value on failure.
+ * Context:
+ *  enabled, ccw device lock not held
+ */
+int ccw_device_set_offline(struct ccw_device *cdev)
 {
 	int ret;
 
@@ -396,8 +396,19 @@
  	return ret;
 }
 
-int
-ccw_device_set_online(struct ccw_device *cdev)
+/**
+ * ccw_device_set_online() - enable a ccw device for I/O
+ * @cdev: target ccw device
+ *
+ * This function first enables @cdev and then calls the driver's set_online()
+ * function for @cdev, if given. If set_online() returns an error, @cdev is
+ * disabled again.
+ * Returns:
+ *   %0 on success and a negative error value on failure.
+ * Context:
+ *  enabled, ccw device lock not held
+ */
+int ccw_device_set_online(struct ccw_device *cdev)
 {
 	int ret;
 
@@ -947,8 +958,7 @@
 		wake_up(&ccw_device_init_wq);
 }
 
-void
-ccw_device_call_sch_unregister(struct work_struct *work)
+static void ccw_device_call_sch_unregister(struct work_struct *work)
 {
 	struct ccw_device_private *priv;
 	struct ccw_device *cdev;
@@ -1101,6 +1111,7 @@
 		 * device, e.g. the console.
 		 */
 		cdev = sch->dev.driver_data;
+		cdev->dev.groups = ccwdev_attr_groups;
 		device_initialize(&cdev->dev);
 		ccw_device_register(cdev);
 		/*
@@ -1326,8 +1337,19 @@
 }
 
 
-struct ccw_device *
-get_ccwdev_by_busid(struct ccw_driver *cdrv, const char *bus_id)
+/**
+ * get_ccwdev_by_busid() - obtain device from a bus id
+ * @cdrv: driver the device is owned by
+ * @bus_id: bus id of the device to be searched
+ *
+ * This function searches all devices owned by @cdrv for a device with a bus
+ * id matching @bus_id.
+ * Returns:
+ *  If a match is found, its reference count of the found device is increased
+ *  and it is returned; else %NULL is returned.
+ */
+struct ccw_device *get_ccwdev_by_busid(struct ccw_driver *cdrv,
+				       const char *bus_id)
 {
 	struct device *dev;
 	struct device_driver *drv;
@@ -1401,16 +1423,34 @@
 	return 0;
 }
 
+static void ccw_device_shutdown(struct device *dev)
+{
+	struct ccw_device *cdev;
+
+	cdev = to_ccwdev(dev);
+	if (cdev->drv && cdev->drv->shutdown)
+		cdev->drv->shutdown(cdev);
+	disable_cmf(cdev);
+}
+
 struct bus_type ccw_bus_type = {
 	.name   = "ccw",
 	.match  = ccw_bus_match,
 	.uevent = ccw_uevent,
 	.probe  = ccw_device_probe,
 	.remove = ccw_device_remove,
+	.shutdown = ccw_device_shutdown,
 };
 
-int
-ccw_driver_register (struct ccw_driver *cdriver)
+/**
+ * ccw_driver_register() - register a ccw driver
+ * @cdriver: driver to be registered
+ *
+ * This function is mainly a wrapper around driver_register().
+ * Returns:
+ *   %0 on success and a negative error value on failure.
+ */
+int ccw_driver_register(struct ccw_driver *cdriver)
 {
 	struct device_driver *drv = &cdriver->driver;
 
@@ -1420,8 +1460,13 @@
 	return driver_register(drv);
 }
 
-void
-ccw_driver_unregister (struct ccw_driver *cdriver)
+/**
+ * ccw_driver_unregister() - deregister a ccw driver
+ * @cdriver: driver to be deregistered
+ *
+ * This function is mainly a wrapper around driver_unregister().
+ */
+void ccw_driver_unregister(struct ccw_driver *cdriver)
 {
 	driver_unregister(&cdriver->driver);
 }
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h
index b66338b..0d40896 100644
--- a/drivers/s390/cio/device.h
+++ b/drivers/s390/cio/device.h
@@ -80,7 +80,6 @@
 int ccw_device_cancel_halt_clear(struct ccw_device *);
 
 void ccw_device_do_unreg_rereg(struct work_struct *);
-void ccw_device_call_sch_unregister(struct work_struct *);
 void ccw_device_move_to_orphanage(struct work_struct *);
 int ccw_device_is_orphan(struct ccw_device *);
 
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 8633dc5..8867443 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -446,7 +446,8 @@
 	if (cdev->private->pgid[last].inf.ps.state1 ==
 	    SNID_STATE1_RESET)
 		/* No previous pgid found */
-		memcpy(&cdev->private->pgid[0], &css[0]->global_pgid,
+		memcpy(&cdev->private->pgid[0],
+		       &channel_subsystems[0]->global_pgid,
 		       sizeof(struct pgid));
 	else
 		/* Use existing pgid */
@@ -543,51 +544,6 @@
 }
 
 
-static void
-ccw_device_nopath_notify(struct work_struct *work)
-{
-	struct ccw_device_private *priv;
-	struct ccw_device *cdev;
-	struct subchannel *sch;
-	int ret;
-	unsigned long flags;
-
-	priv = container_of(work, struct ccw_device_private, kick_work);
-	cdev = priv->cdev;
-	spin_lock_irqsave(cdev->ccwlock, flags);
-	sch = to_subchannel(cdev->dev.parent);
-	/* Extra sanity. */
-	if (sch->lpm)
-		goto out_unlock;
-	if (sch->driver && sch->driver->notify) {
-		spin_unlock_irqrestore(cdev->ccwlock, flags);
-		ret = sch->driver->notify(&sch->dev, CIO_NO_PATH);
-		spin_lock_irqsave(cdev->ccwlock, flags);
-	} else
-		ret = 0;
-	if (!ret) {
-		if (get_device(&sch->dev)) {
-			/* Driver doesn't want to keep device. */
-			cio_disable_subchannel(sch);
-			if (get_device(&cdev->dev)) {
-				PREPARE_WORK(&cdev->private->kick_work,
-					     ccw_device_call_sch_unregister);
-				queue_work(ccw_device_work,
-					   &cdev->private->kick_work);
-			} else
-				put_device(&sch->dev);
-		}
-	} 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);
-	}
-out_unlock:
-	spin_unlock_irqrestore(cdev->ccwlock, flags);
-}
-
 void
 ccw_device_verify_done(struct ccw_device *cdev, int err)
 {
@@ -631,12 +587,9 @@
 	default:
 		/* Reset oper notify indication after verify error. */
 		cdev->private->flags.donotify = 0;
-		if (cdev->online) {
-			PREPARE_WORK(&cdev->private->kick_work,
-				     ccw_device_nopath_notify);
-			queue_work(ccw_device_notify_work,
-				   &cdev->private->kick_work);
-		} else
+		if (cdev->online)
+			dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
+		else
 			ccw_device_done(cdev, DEV_STATE_NOT_OPER);
 		break;
 	}
@@ -690,11 +643,7 @@
 		break;
 	default:
 		cdev->private->flags.donotify = 0;
-		if (get_device(&cdev->dev)) {
-			PREPARE_WORK(&cdev->private->kick_work,
-				     ccw_device_call_sch_unregister);
-			queue_work(ccw_device_work, &cdev->private->kick_work);
-		}
+		dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
 		ccw_device_done(cdev, DEV_STATE_NOT_OPER);
 		break;
 	}
@@ -765,59 +714,16 @@
 }
 
 /*
- * Handle not operational event while offline.
+ * Handle not operational event in non-special state.
  */
-static void
-ccw_device_offline_notoper(struct ccw_device *cdev, enum dev_event dev_event)
+static void ccw_device_generic_notoper(struct ccw_device *cdev,
+				       enum dev_event dev_event)
 {
 	struct subchannel *sch;
 
 	cdev->private->state = DEV_STATE_NOT_OPER;
 	sch = to_subchannel(cdev->dev.parent);
-	if (get_device(&cdev->dev)) {
-		PREPARE_WORK(&cdev->private->kick_work,
-			     ccw_device_call_sch_unregister);
-		queue_work(ccw_device_work, &cdev->private->kick_work);
-	}
-	wake_up(&cdev->private->wait_q);
-}
-
-/*
- * Handle not operational event while online.
- */
-static void
-ccw_device_online_notoper(struct ccw_device *cdev, enum dev_event dev_event)
-{
-	struct subchannel *sch;
-	int ret;
-
-	sch = to_subchannel(cdev->dev.parent);
-	if (sch->driver->notify) {
-		spin_unlock_irq(cdev->ccwlock);
-		ret = sch->driver->notify(&sch->dev,
-					  sch->lpm ? CIO_GONE : CIO_NO_PATH);
-		spin_lock_irq(cdev->ccwlock);
-	} else
-		ret = 0;
-	if (ret) {
-		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;
-	}
-	cdev->private->state = DEV_STATE_NOT_OPER;
-	cio_disable_subchannel(sch);
-	if (sch->schib.scsw.actl != 0) {
-		// FIXME: not-oper indication to device driver ?
-		ccw_device_call_handler(cdev);
-	}
-	if (get_device(&cdev->dev)) {
-		PREPARE_WORK(&cdev->private->kick_work,
-			     ccw_device_call_sch_unregister);
-		queue_work(ccw_device_work, &cdev->private->kick_work);
-	}
-	wake_up(&cdev->private->wait_q);
+	css_schedule_eval(sch->schid);
 }
 
 /*
@@ -915,18 +821,9 @@
 		cdev->private->state = DEV_STATE_TIMEOUT_KILL;
 		return;
 	}
-	if (ret == -ENODEV) {
-		struct subchannel *sch;
-
-		sch = to_subchannel(cdev->dev.parent);
-		if (!sch->lpm) {
-			PREPARE_WORK(&cdev->private->kick_work,
-				     ccw_device_nopath_notify);
-			queue_work(ccw_device_notify_work,
-				   &cdev->private->kick_work);
-		} else
-			dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
-	} else if (cdev->handler)
+	if (ret == -ENODEV)
+		dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
+	else if (cdev->handler)
 		cdev->handler(cdev, cdev->private->intparm,
 			      ERR_PTR(-ETIMEDOUT));
 }
@@ -1233,7 +1130,7 @@
 		[DEV_EVENT_VERIFY]	= ccw_device_nop,
 	},
 	[DEV_STATE_SENSE_PGID] = {
-		[DEV_EVENT_NOTOPER]	= ccw_device_online_notoper,
+		[DEV_EVENT_NOTOPER]	= ccw_device_generic_notoper,
 		[DEV_EVENT_INTERRUPT]	= ccw_device_sense_pgid_irq,
 		[DEV_EVENT_TIMEOUT]	= ccw_device_onoff_timeout,
 		[DEV_EVENT_VERIFY]	= ccw_device_nop,
@@ -1245,50 +1142,50 @@
 		[DEV_EVENT_VERIFY]	= ccw_device_nop,
 	},
 	[DEV_STATE_OFFLINE] = {
-		[DEV_EVENT_NOTOPER]	= ccw_device_offline_notoper,
+		[DEV_EVENT_NOTOPER]	= ccw_device_generic_notoper,
 		[DEV_EVENT_INTERRUPT]	= ccw_device_offline_irq,
 		[DEV_EVENT_TIMEOUT]	= ccw_device_nop,
 		[DEV_EVENT_VERIFY]	= ccw_device_nop,
 	},
 	[DEV_STATE_VERIFY] = {
-		[DEV_EVENT_NOTOPER]	= ccw_device_online_notoper,
+		[DEV_EVENT_NOTOPER]	= ccw_device_generic_notoper,
 		[DEV_EVENT_INTERRUPT]	= ccw_device_verify_irq,
 		[DEV_EVENT_TIMEOUT]	= ccw_device_onoff_timeout,
 		[DEV_EVENT_VERIFY]	= ccw_device_delay_verify,
 	},
 	[DEV_STATE_ONLINE] = {
-		[DEV_EVENT_NOTOPER]	= ccw_device_online_notoper,
+		[DEV_EVENT_NOTOPER]	= ccw_device_generic_notoper,
 		[DEV_EVENT_INTERRUPT]	= ccw_device_irq,
 		[DEV_EVENT_TIMEOUT]	= ccw_device_online_timeout,
 		[DEV_EVENT_VERIFY]	= ccw_device_online_verify,
 	},
 	[DEV_STATE_W4SENSE] = {
-		[DEV_EVENT_NOTOPER]	= ccw_device_online_notoper,
+		[DEV_EVENT_NOTOPER]	= ccw_device_generic_notoper,
 		[DEV_EVENT_INTERRUPT]	= ccw_device_w4sense,
 		[DEV_EVENT_TIMEOUT]	= ccw_device_nop,
 		[DEV_EVENT_VERIFY]	= ccw_device_online_verify,
 	},
 	[DEV_STATE_DISBAND_PGID] = {
-		[DEV_EVENT_NOTOPER]	= ccw_device_online_notoper,
+		[DEV_EVENT_NOTOPER]	= ccw_device_generic_notoper,
 		[DEV_EVENT_INTERRUPT]	= ccw_device_disband_irq,
 		[DEV_EVENT_TIMEOUT]	= ccw_device_onoff_timeout,
 		[DEV_EVENT_VERIFY]	= ccw_device_nop,
 	},
 	[DEV_STATE_BOXED] = {
-		[DEV_EVENT_NOTOPER]	= ccw_device_offline_notoper,
+		[DEV_EVENT_NOTOPER]	= ccw_device_generic_notoper,
 		[DEV_EVENT_INTERRUPT]	= ccw_device_stlck_done,
 		[DEV_EVENT_TIMEOUT]	= ccw_device_stlck_done,
 		[DEV_EVENT_VERIFY]	= ccw_device_nop,
 	},
 	/* states to wait for i/o completion before doing something */
 	[DEV_STATE_CLEAR_VERIFY] = {
-		[DEV_EVENT_NOTOPER]     = ccw_device_online_notoper,
+		[DEV_EVENT_NOTOPER]	= ccw_device_generic_notoper,
 		[DEV_EVENT_INTERRUPT]   = ccw_device_clear_verify,
 		[DEV_EVENT_TIMEOUT]	= ccw_device_nop,
 		[DEV_EVENT_VERIFY]	= ccw_device_nop,
 	},
 	[DEV_STATE_TIMEOUT_KILL] = {
-		[DEV_EVENT_NOTOPER]	= ccw_device_online_notoper,
+		[DEV_EVENT_NOTOPER]	= ccw_device_generic_notoper,
 		[DEV_EVENT_INTERRUPT]	= ccw_device_killing_irq,
 		[DEV_EVENT_TIMEOUT]	= ccw_device_killing_timeout,
 		[DEV_EVENT_VERIFY]	= ccw_device_nop, //FIXME
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index 14eba85..7fd2dad 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -25,6 +25,16 @@
 #include "device.h"
 #include "chp.h"
 
+/**
+ * ccw_device_set_options_mask() - set some options and unset the rest
+ * @cdev: device for which the options are to be set
+ * @flags: options to be set
+ *
+ * All flags specified in @flags are set, all flags not specified in @flags
+ * are cleared.
+ * Returns:
+ *   %0 on success, -%EINVAL on an invalid flag combination.
+ */
 int ccw_device_set_options_mask(struct ccw_device *cdev, unsigned long flags)
 {
        /*
@@ -40,6 +50,15 @@
 	return 0;
 }
 
+/**
+ * ccw_device_set_options() - set some options
+ * @cdev: device for which the options are to be set
+ * @flags: options to be set
+ *
+ * All flags specified in @flags are set, the remainder is left untouched.
+ * Returns:
+ *   %0 on success, -%EINVAL if an invalid flag combination would ensue.
+ */
 int ccw_device_set_options(struct ccw_device *cdev, unsigned long flags)
 {
        /*
@@ -59,6 +78,13 @@
 	return 0;
 }
 
+/**
+ * ccw_device_clear_options() - clear some options
+ * @cdev: device for which the options are to be cleared
+ * @flags: options to be cleared
+ *
+ * All flags specified in @flags are cleared, the remainder is left untouched.
+ */
 void ccw_device_clear_options(struct ccw_device *cdev, unsigned long flags)
 {
 	cdev->private->options.fast &= (flags & CCWDEV_EARLY_NOTIFICATION) == 0;
@@ -67,8 +93,22 @@
 	cdev->private->options.force &= (flags & CCWDEV_ALLOW_FORCE) == 0;
 }
 
-int
-ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
+/**
+ * ccw_device_clear() - terminate I/O request processing
+ * @cdev: target ccw device
+ * @intparm: interruption parameter; value is only used if no I/O is
+ *	     outstanding, otherwise the intparm associated with the I/O request
+ *	     is returned
+ *
+ * ccw_device_clear() calls csch on @cdev's subchannel.
+ * Returns:
+ *  %0 on success,
+ *  -%ENODEV on device not operational,
+ *  -%EINVAL on invalid device state.
+ * Context:
+ *  Interrupts disabled, ccw device lock held
+ */
+int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
 {
 	struct subchannel *sch;
 	int ret;
@@ -89,10 +129,33 @@
 	return ret;
 }
 
-int
-ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
-		     unsigned long intparm, __u8 lpm, __u8 key,
-		     unsigned long flags)
+/**
+ * ccw_device_start_key() - start a s390 channel program with key
+ * @cdev: target ccw device
+ * @cpa: logical start address of channel program
+ * @intparm: user specific interruption parameter; will be presented back to
+ *	     @cdev's interrupt handler. Allows a device driver to associate
+ *	     the interrupt with a 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: storage key to be used for the I/O
+ * @flags: additional flags; defines the action to be performed for I/O
+ *	   processing.
+ *
+ * Start a S/390 channel program. When the interrupt arrives, the
+ * IRQ handler is called, either immediately, delayed (dev-end missing,
+ * or sense required) or never (no IRQ handler registered).
+ * Returns:
+ *  %0, if the operation was successful;
+ *  -%EBUSY, if the device is busy, or status pending;
+ *  -%EACCES, if no path specified in @lpm is operational;
+ *  -%ENODEV, if the device is not operational.
+ * Context:
+ *  Interrupts disabled, ccw device lock held
+ */
+int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
+			 unsigned long intparm, __u8 lpm, __u8 key,
+			 unsigned long flags)
 {
 	struct subchannel *sch;
 	int ret;
@@ -135,11 +198,38 @@
 	return ret;
 }
 
-
-int
-ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa,
-			     unsigned long intparm, __u8 lpm, __u8 key,
-			     unsigned long flags, int expires)
+/**
+ * ccw_device_start_timeout_key() - start a s390 channel program with timeout and key
+ * @cdev: target ccw device
+ * @cpa: logical start address of channel program
+ * @intparm: user specific interruption parameter; will be presented back to
+ *	     @cdev's interrupt handler. Allows a device driver to associate
+ *	     the interrupt with a 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: storage key to be used for the I/O
+ * @flags: additional flags; defines the action to be performed for I/O
+ *	   processing.
+ * @expires: timeout value in jiffies
+ *
+ * Start a S/390 channel program. When the interrupt arrives, the
+ * IRQ handler is called, either immediately, delayed (dev-end missing,
+ * or sense required) or never (no IRQ handler registered).
+ * This function notifies the device driver if the channel program has not
+ * completed during the time specified by @expires. If a timeout occurs, the
+ * channel program is terminated via xsch, hsch or csch, and the device's
+ * interrupt handler will be called with an irb containing ERR_PTR(-%ETIMEDOUT).
+ * Returns:
+ *  %0, if the operation was successful;
+ *  -%EBUSY, if the device is busy, or status pending;
+ *  -%EACCES, if no path specified in @lpm is operational;
+ *  -%ENODEV, if the device is not operational.
+ * Context:
+ *  Interrupts disabled, ccw device lock held
+ */
+int ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa,
+				 unsigned long intparm, __u8 lpm, __u8 key,
+				 unsigned long flags, int expires)
 {
 	int ret;
 
@@ -152,18 +242,67 @@
 	return ret;
 }
 
-int
-ccw_device_start(struct ccw_device *cdev, struct ccw1 *cpa,
-		 unsigned long intparm, __u8 lpm, unsigned long flags)
+/**
+ * ccw_device_start() - start a s390 channel program
+ * @cdev: target ccw device
+ * @cpa: logical start address of channel program
+ * @intparm: user specific interruption parameter; will be presented back to
+ *	     @cdev's interrupt handler. Allows a device driver to associate
+ *	     the interrupt with a 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.
+ * @flags: additional flags; defines the action to be performed for I/O
+ *	   processing.
+ *
+ * Start a S/390 channel program. When the interrupt arrives, the
+ * IRQ handler is called, either immediately, delayed (dev-end missing,
+ * or sense required) or never (no IRQ handler registered).
+ * Returns:
+ *  %0, if the operation was successful;
+ *  -%EBUSY, if the device is busy, or status pending;
+ *  -%EACCES, if no path specified in @lpm is operational;
+ *  -%ENODEV, if the device is not operational.
+ * Context:
+ *  Interrupts disabled, ccw device lock held
+ */
+int ccw_device_start(struct ccw_device *cdev, struct ccw1 *cpa,
+		     unsigned long intparm, __u8 lpm, unsigned long flags)
 {
 	return ccw_device_start_key(cdev, cpa, intparm, lpm,
 				    PAGE_DEFAULT_KEY, flags);
 }
 
-int
-ccw_device_start_timeout(struct ccw_device *cdev, struct ccw1 *cpa,
-			 unsigned long intparm, __u8 lpm, unsigned long flags,
-			 int expires)
+/**
+ * ccw_device_start_timeout() - start a s390 channel program with timeout
+ * @cdev: target ccw device
+ * @cpa: logical start address of channel program
+ * @intparm: user specific interruption parameter; will be presented back to
+ *	     @cdev's interrupt handler. Allows a device driver to associate
+ *	     the interrupt with a 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.
+ * @flags: additional flags; defines the action to be performed for I/O
+ *	   processing.
+ * @expires: timeout value in jiffies
+ *
+ * Start a S/390 channel program. When the interrupt arrives, the
+ * IRQ handler is called, either immediately, delayed (dev-end missing,
+ * or sense required) or never (no IRQ handler registered).
+ * This function notifies the device driver if the channel program has not
+ * completed during the time specified by @expires. If a timeout occurs, the
+ * channel program is terminated via xsch, hsch or csch, and the device's
+ * interrupt handler will be called with an irb containing ERR_PTR(-%ETIMEDOUT).
+ * Returns:
+ *  %0, if the operation was successful;
+ *  -%EBUSY, if the device is busy, or status pending;
+ *  -%EACCES, if no path specified in @lpm is operational;
+ *  -%ENODEV, if the device is not operational.
+ * Context:
+ *  Interrupts disabled, ccw device lock held
+ */
+int ccw_device_start_timeout(struct ccw_device *cdev, struct ccw1 *cpa,
+			     unsigned long intparm, __u8 lpm,
+			     unsigned long flags, int expires)
 {
 	return ccw_device_start_timeout_key(cdev, cpa, intparm, lpm,
 					    PAGE_DEFAULT_KEY, flags,
@@ -171,8 +310,23 @@
 }
 
 
-int
-ccw_device_halt(struct ccw_device *cdev, unsigned long intparm)
+/**
+ * ccw_device_halt() - halt I/O request processing
+ * @cdev: target ccw device
+ * @intparm: interruption parameter; value is only used if no I/O is
+ *	     outstanding, otherwise the intparm associated with the I/O request
+ *	     is returned
+ *
+ * ccw_device_halt() calls hsch on @cdev's subchannel.
+ * Returns:
+ *  %0 on success,
+ *  -%ENODEV on device not operational,
+ *  -%EINVAL on invalid device state,
+ *  -%EBUSY on device busy or interrupt pending.
+ * Context:
+ *  Interrupts disabled, ccw device lock held
+ */
+int ccw_device_halt(struct ccw_device *cdev, unsigned long intparm)
 {
 	struct subchannel *sch;
 	int ret;
@@ -193,8 +347,20 @@
 	return ret;
 }
 
-int
-ccw_device_resume(struct ccw_device *cdev)
+/**
+ * ccw_device_resume() - resume channel program execution
+ * @cdev: target ccw device
+ *
+ * ccw_device_resume() calls rsch on @cdev's subchannel.
+ * Returns:
+ *  %0 on success,
+ *  -%ENODEV on device not operational,
+ *  -%EINVAL on invalid device state,
+ *  -%EBUSY on device busy or interrupt pending.
+ * Context:
+ *  Interrupts disabled, ccw device lock held
+ */
+int ccw_device_resume(struct ccw_device *cdev)
 {
 	struct subchannel *sch;
 
@@ -260,11 +426,21 @@
 	return 1;
 }
 
-/*
- * Search for CIW command in extended sense data.
+/**
+ * ccw_device_get_ciw() - Search for CIW command in extended sense data.
+ * @cdev: ccw device to inspect
+ * @ct: command type to look for
+ *
+ * During SenseID, command information words (CIWs) describing special
+ * commands available to the device may have been stored in the extended
+ * sense data. This function searches for CIWs of a specified command
+ * type in the extended sense data.
+ * Returns:
+ *  %NULL if no extended sense data has been stored or if no CIW of the
+ *  specified command type could be found,
+ *  else a pointer to the CIW of the specified command type.
  */
-struct ciw *
-ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct)
+struct ciw *ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct)
 {
 	int ciw_cnt;
 
@@ -276,8 +452,14 @@
 	return NULL;
 }
 
-__u8
-ccw_device_get_path_mask(struct ccw_device *cdev)
+/**
+ * ccw_device_get_path_mask() - get currently available paths
+ * @cdev: ccw device to be queried
+ * Returns:
+ *  %0 if no subchannel for the device is available,
+ *  else the mask of currently available paths for the ccw device's subchannel.
+ */
+__u8 ccw_device_get_path_mask(struct ccw_device *cdev)
 {
 	struct subchannel *sch;
 
@@ -357,8 +539,7 @@
 	return ret;
 }
 
-void *
-ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no)
+void *ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no)
 {
 	struct subchannel *sch;
 	struct chp_id chpid;
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c
index d8d4798..40a3208 100644
--- a/drivers/s390/cio/qdio.c
+++ b/drivers/s390/cio/qdio.c
@@ -1024,9 +1024,9 @@
 }
 
 static void
-qdio_outbound_processing(struct qdio_q *q)
+qdio_outbound_processing(unsigned long q)
 {
-	__qdio_outbound_processing(q);
+	__qdio_outbound_processing((struct qdio_q *) q);
 }
 
 /************************* INBOUND ROUTINES *******************************/
@@ -1449,9 +1449,10 @@
 }
 
 static void
-tiqdio_inbound_processing(struct qdio_q *q)
+tiqdio_inbound_processing(unsigned long q)
 {
-	__tiqdio_inbound_processing(q, atomic_read(&spare_indicator_usecount));
+	__tiqdio_inbound_processing((struct qdio_q *) q,
+				    atomic_read(&spare_indicator_usecount));
 }
 
 static void
@@ -1494,9 +1495,9 @@
 }
 
 static void
-qdio_inbound_processing(struct qdio_q *q)
+qdio_inbound_processing(unsigned long q)
 {
-	__qdio_inbound_processing(q);
+	__qdio_inbound_processing((struct qdio_q *) q);
 }
 
 /************************* MAIN ROUTINES *******************************/
@@ -1760,12 +1761,15 @@
 		q->handler=input_handler;
 		q->dev_st_chg_ind=irq_ptr->dev_st_chg_ind;
 
-		q->tasklet.data=(unsigned long)q;
 		/* q->is_thinint_q isn't valid at this time, but
-		 * irq_ptr->is_thinint_irq is */
-		q->tasklet.func=(void(*)(unsigned long))
-			((irq_ptr->is_thinint_irq)?&tiqdio_inbound_processing:
-			 &qdio_inbound_processing);
+		 * irq_ptr->is_thinint_irq is
+		 */
+		if (irq_ptr->is_thinint_irq)
+			tasklet_init(&q->tasklet, tiqdio_inbound_processing,
+				     (unsigned long) q);
+		else
+			tasklet_init(&q->tasklet, qdio_inbound_processing,
+				     (unsigned long) q);
 
 		/* actually this is not used for inbound queues. yet. */
 		atomic_set(&q->busy_siga_counter,0);
@@ -1836,13 +1840,10 @@
 		q->last_move_ftc=0;
 		q->handler=output_handler;
 
-		q->tasklet.data=(unsigned long)q;
-		q->tasklet.func=(void(*)(unsigned long))
-			&qdio_outbound_processing;
-		q->timer.function=(void(*)(unsigned long))
-			&qdio_outbound_processing;
-		q->timer.data = (long)q;
-		init_timer(&q->timer);
+		tasklet_init(&q->tasklet, qdio_outbound_processing,
+			     (unsigned long) q);
+		setup_timer(&q->timer, qdio_outbound_processing,
+			    (unsigned long) q);
 
 		atomic_set(&q->busy_siga_counter,0);
 		q->timing.busy_start=0;
@@ -3726,7 +3727,7 @@
 #endif /* CONFIG_64BIT */
 		}
 	} else {
-		QDIO_PRINT_WARN("QDIO performance_stats: write 0 or 1 to this file!\n");
+		QDIO_PRINT_ERR("QDIO performance_stats: write 0 or 1 to this file!\n");
 		return -EINVAL;
 	}
 	return count;
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index 90bd220..67aaff3 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -458,28 +458,22 @@
  * uevent function for AP devices. It sets up a single environment
  * variable DEV_TYPE which contains the hardware device type.
  */
-static int ap_uevent (struct device *dev, char **envp, int num_envp,
-		       char *buffer, int buffer_size)
+static int ap_uevent (struct device *dev, struct kobj_uevent_env *env)
 {
 	struct ap_device *ap_dev = to_ap_dev(dev);
-	int retval = 0, length = 0, i = 0;
+	int retval = 0;
 
 	if (!ap_dev)
 		return -ENODEV;
 
 	/* Set up DEV_TYPE environment variable. */
-	retval = add_uevent_var(envp, num_envp, &i,
-				buffer, buffer_size, &length,
-				"DEV_TYPE=%04X", ap_dev->device_type);
+	retval = add_uevent_var(env, "DEV_TYPE=%04X", ap_dev->device_type);
 	if (retval)
 		return retval;
 
 	/* Add MODALIAS= */
-	retval = add_uevent_var(envp, num_envp, &i,
-				buffer, buffer_size, &length,
-				"MODALIAS=ap:t%02X", ap_dev->device_type);
+	retval = add_uevent_var(env, "MODALIAS=ap:t%02X", ap_dev->device_type);
 
-	envp[i] = NULL;
 	return retval;
 }
 
@@ -1231,8 +1225,9 @@
 {
 	int i;
 
-	for (i = 0; i < AP_DEVICES; i++)
-		ap_reset_queue(AP_MKQID(i, ap_domain_index));
+	if (ap_domain_index != -1)
+		for (i = 0; i < AP_DEVICES; i++)
+			ap_reset_queue(AP_MKQID(i, ap_domain_index));
 }
 
 static void ap_reset_all(void)
diff --git a/drivers/s390/crypto/zcrypt_mono.c b/drivers/s390/crypto/zcrypt_mono.c
index 2a9349a..44253fd 100644
--- a/drivers/s390/crypto/zcrypt_mono.c
+++ b/drivers/s390/crypto/zcrypt_mono.c
@@ -45,7 +45,7 @@
 /**
  * The module initialization code.
  */
-int __init zcrypt_init(void)
+static int __init zcrypt_init(void)
 {
 	int rc;
 
@@ -86,7 +86,7 @@
 /**
  * The module termination code.
  */
-void __exit zcrypt_exit(void)
+static void __exit zcrypt_exit(void)
 {
 	zcrypt_cex2a_exit();
 	zcrypt_pcixcc_exit();
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c
index 6494878..70b9ddc 100644
--- a/drivers/s390/crypto/zcrypt_pcixcc.c
+++ b/drivers/s390/crypto/zcrypt_pcixcc.c
@@ -277,7 +277,7 @@
 	};
 	struct {
 		struct type6_hdr hdr;
-		struct ica_CPRBX cprbx;
+		struct CPRBX cprbx;
 	} __attribute__((packed)) *msg = ap_msg->message;
 
 	int rcblen = CEIL4(xcRB->request_control_blk_length);
@@ -432,14 +432,17 @@
 		}
 		if (service_rc == 8 && service_rs == 770) {
 			PDEBUG("Invalid key length on PCIXCC/CEX2C\n");
-			zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
-			return -EAGAIN;
+			return -EINVAL;
 		}
 		if (service_rc == 8 && service_rs == 783) {
 			PDEBUG("Extended bitlengths not enabled on PCIXCC/CEX2C\n");
 			zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
 			return -EAGAIN;
 		}
+		if (service_rc == 12 && service_rs == 769) {
+			PDEBUG("Invalid key on PCIXCC/CEX2C\n");
+			return -EINVAL;
+		}
 		PRINTK("Unknown service rc/rs (PCIXCC/CEX2C): %d/%d\n",
 		       service_rc, service_rs);
 		zdev->online = 0;
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.h b/drivers/s390/crypto/zcrypt_pcixcc.h
index a78ff30..8cb7d7a 100644
--- a/drivers/s390/crypto/zcrypt_pcixcc.h
+++ b/drivers/s390/crypto/zcrypt_pcixcc.h
@@ -28,51 +28,6 @@
 #ifndef _ZCRYPT_PCIXCC_H_
 #define _ZCRYPT_PCIXCC_H_
 
-/**
- * CPRBX
- *	  Note that all shorts and ints are big-endian.
- *	  All pointer fields are 16 bytes long, and mean nothing.
- *
- *	  A request CPRB is followed by a request_parameter_block.
- *
- *	  The request (or reply) parameter block is organized thus:
- *	    function code
- *	    VUD block
- *	    key block
- */
-struct CPRBX {
-	unsigned short cprb_len;	/* CPRB length	      220	 */
-	unsigned char  cprb_ver_id;	/* CPRB version id.   0x02	 */
-	unsigned char  pad_000[3];	/* Alignment pad bytes		 */
-	unsigned char  func_id[2];	/* function id	      0x5432	 */
-	unsigned char  cprb_flags[4];	/* Flags			 */
-	unsigned int   req_parml;	/* request parameter buffer len	 */
-	unsigned int   req_datal;	/* request data buffer		 */
-	unsigned int   rpl_msgbl;	/* reply  message block length	 */
-	unsigned int   rpld_parml;	/* replied parameter block len	 */
-	unsigned int   rpl_datal;	/* reply data block len		 */
-	unsigned int   rpld_datal;	/* replied data block len	 */
-	unsigned int   req_extbl;	/* request extension block len	 */
-	unsigned char  pad_001[4];	/* reserved			 */
-	unsigned int   rpld_extbl;	/* replied extension block len	 */
-	unsigned char  req_parmb[16];	/* request parm block 'address'	 */
-	unsigned char  req_datab[16];	/* request data block 'address'	 */
-	unsigned char  rpl_parmb[16];	/* reply parm block 'address'	 */
-	unsigned char  rpl_datab[16];	/* reply data block 'address'	 */
-	unsigned char  req_extb[16];	/* request extension block 'addr'*/
-	unsigned char  rpl_extb[16];	/* reply extension block 'addres'*/
-	unsigned short ccp_rtcode;	/* server return code		 */
-	unsigned short ccp_rscode;	/* server reason code		 */
-	unsigned int   mac_data_len;	/* Mac Data Length		 */
-	unsigned char  logon_id[8];	/* Logon Identifier		 */
-	unsigned char  mac_value[8];	/* Mac Value			 */
-	unsigned char  mac_content_flgs;/* Mac content flag byte	 */
-	unsigned char  pad_002;		/* Alignment			 */
-	unsigned short domain;		/* Domain			 */
-	unsigned char  pad_003[12];	/* Domain masks			 */
-	unsigned char  pad_004[36];	/* reserved			 */
-} __attribute__((packed));
-
 int zcrypt_pcixcc_init(void);
 void zcrypt_pcixcc_exit(void);
 
diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c
index 1c8f71a..c0d1c0e 100644
--- a/drivers/s390/scsi/zfcp_ccw.c
+++ b/drivers/s390/scsi/zfcp_ccw.c
@@ -28,7 +28,7 @@
 static int zfcp_ccw_set_online(struct ccw_device *);
 static int zfcp_ccw_set_offline(struct ccw_device *);
 static int zfcp_ccw_notify(struct ccw_device *, int);
-static void zfcp_ccw_shutdown(struct device *);
+static void zfcp_ccw_shutdown(struct ccw_device *);
 
 static struct ccw_device_id zfcp_ccw_device_id[] = {
 	{CCW_DEVICE_DEVTYPE(ZFCP_CONTROL_UNIT_TYPE,
@@ -51,9 +51,7 @@
 	.set_online  = zfcp_ccw_set_online,
 	.set_offline = zfcp_ccw_set_offline,
 	.notify      = zfcp_ccw_notify,
-	.driver      = {
-		.shutdown = zfcp_ccw_shutdown,
-	},
+	.shutdown    = zfcp_ccw_shutdown,
 };
 
 MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id);
@@ -277,12 +275,12 @@
  * Makes sure that QDIO queues are down when the system gets stopped.
  */
 static void
-zfcp_ccw_shutdown(struct device *dev)
+zfcp_ccw_shutdown(struct ccw_device *cdev)
 {
 	struct zfcp_adapter *adapter;
 
 	down(&zfcp_data.config_sema);
-	adapter = dev_get_drvdata(dev);
+	adapter = dev_get_drvdata(&cdev->dev);
 	zfcp_erp_adapter_shutdown(adapter, 0);
 	zfcp_erp_wait(adapter);
 	up(&zfcp_data.config_sema);
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
index 5f32124..ffa3bf75 100644
--- a/drivers/s390/scsi/zfcp_dbf.c
+++ b/drivers/s390/scsi/zfcp_dbf.c
@@ -19,8 +19,8 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <asm/debug.h>
 #include <linux/ctype.h>
+#include <asm/debug.h>
 #include "zfcp_ext.h"
 
 static u32 dbfsize = 4;
@@ -35,17 +35,17 @@
 zfcp_dbf_stck(char *out_buf, const char *label, unsigned long long stck)
 {
 	unsigned long long sec;
-	struct timespec xtime;
+	struct timespec dbftime;
 	int len = 0;
 
 	stck -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096);
 	sec = stck >> 12;
 	do_div(sec, 1000000);
-	xtime.tv_sec = sec;
+	dbftime.tv_sec = sec;
 	stck -= (sec * 1000000) << 12;
-	xtime.tv_nsec = ((stck * 1000) >> 12);
+	dbftime.tv_nsec = ((stck * 1000) >> 12);
 	len += sprintf(out_buf + len, "%-24s%011lu:%06lu\n",
-		       label, xtime.tv_sec, xtime.tv_nsec);
+		       label, dbftime.tv_sec, dbftime.tv_nsec);
 
 	return len;
 }
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index d8cd75c..16b4418 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -54,7 +54,7 @@
 static int zfcp_erp_strategy_statechange(int, u32, struct zfcp_adapter *,
 					 struct zfcp_port *,
 					 struct zfcp_unit *, int);
-static inline int zfcp_erp_strategy_statechange_detected(atomic_t *, u32);
+static int zfcp_erp_strategy_statechange_detected(atomic_t *, u32);
 static int zfcp_erp_strategy_followup_actions(int, struct zfcp_adapter *,
 					      struct zfcp_port *,
 					      struct zfcp_unit *, int);
@@ -106,8 +106,8 @@
 static void zfcp_erp_action_ready(struct zfcp_erp_action *);
 static int  zfcp_erp_action_exists(struct zfcp_erp_action *);
 
-static inline void zfcp_erp_action_to_ready(struct zfcp_erp_action *);
-static inline void zfcp_erp_action_to_running(struct zfcp_erp_action *);
+static void zfcp_erp_action_to_ready(struct zfcp_erp_action *);
+static void zfcp_erp_action_to_running(struct zfcp_erp_action *);
 
 static void zfcp_erp_memwait_handler(unsigned long);
 
@@ -952,7 +952,7 @@
  *		action gets an appropriate flag and will be processed
  *		accordingly
  */
-void zfcp_erp_timeout_handler(unsigned long data)
+static void zfcp_erp_timeout_handler(unsigned long data)
 {
 	struct zfcp_erp_action *erp_action = (struct zfcp_erp_action *) data;
 	struct zfcp_adapter *adapter = erp_action->adapter;
@@ -1491,7 +1491,7 @@
 	return retval;
 }
 
-static inline int
+static int
 zfcp_erp_strategy_statechange_detected(atomic_t * target_status, u32 erp_status)
 {
 	return
@@ -2001,7 +2001,7 @@
  * returns:	0 - successful setup
  *		!0 - failed setup
  */
-int
+static int
 zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action)
 {
 	int retval;
@@ -3248,8 +3248,7 @@
 		zfcp_erp_action_dismiss(&unit->erp_action);
 }
 
-static inline void
-zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
+static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
 {
 	struct zfcp_adapter *adapter = erp_action->adapter;
 
@@ -3258,8 +3257,7 @@
 	list_move(&erp_action->list, &erp_action->adapter->erp_running_head);
 }
 
-static inline void
-zfcp_erp_action_to_ready(struct zfcp_erp_action *erp_action)
+static void zfcp_erp_action_to_ready(struct zfcp_erp_action *erp_action)
 {
 	struct zfcp_adapter *adapter = erp_action->adapter;
 
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 34cdce6..ede9986 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -277,16 +277,11 @@
 	return (sdp->inq_periph_qual == SCSI_INQ_PQ_CON)? 1: 0;
 }
 
-static int scsi_bus_uevent(struct device *dev, char **envp, int num_envp,
-		           char *buffer, int buffer_size)
+static int scsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct scsi_device *sdev = to_scsi_device(dev);
-	int i = 0;
-	int length = 0;
 
-	add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
-		       "MODALIAS=" SCSI_DEVICE_MODALIAS_FMT, sdev->type);
-	envp[i] = NULL;
+	add_uevent_var(env, "MODALIAS=" SCSI_DEVICE_MODALIAS_FMT, sdev->type);
 	return 0;
 }
 
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index e84d215..bcb8dd5 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -67,14 +67,11 @@
 	return strncmp(spi->modalias, drv->name, BUS_ID_SIZE) == 0;
 }
 
-static int spi_uevent(struct device *dev, char **envp, int num_envp,
-		char *buffer, int buffer_size)
+static int spi_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	const struct spi_device		*spi = to_spi_device(dev);
 
-	envp[0] = buffer;
-	snprintf(buffer, buffer_size, "MODALIAS=%s", spi->modalias);
-	envp[1] = NULL;
+	add_uevent_var(env, "MODALIAS=%s", spi->modalias);
 	return 0;
 }
 
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index ac49b15..516a640 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -28,27 +28,7 @@
 
 obj-$(CONFIG_USB_SERIAL)	+= serial/
 
-obj-$(CONFIG_USB_ADUTUX)	+= misc/
-obj-$(CONFIG_USB_APPLEDISPLAY)	+= misc/
-obj-$(CONFIG_USB_AUERSWALD)	+= misc/
-obj-$(CONFIG_USB_BERRY_CHARGE)	+= misc/
-obj-$(CONFIG_USB_CYPRESS_CY7C63)+= misc/
-obj-$(CONFIG_USB_CYTHERM)	+= misc/
-obj-$(CONFIG_USB_EMI26)		+= misc/
-obj-$(CONFIG_USB_EMI62)		+= misc/
-obj-$(CONFIG_USB_FTDI_ELAN)	+= misc/
-obj-$(CONFIG_USB_IDMOUSE)	+= misc/
-obj-$(CONFIG_USB_LCD)		+= misc/
-obj-$(CONFIG_USB_LD)		+= misc/
-obj-$(CONFIG_USB_LED)		+= misc/
-obj-$(CONFIG_USB_LEGOTOWER)	+= misc/
-obj-$(CONFIG_USB_PHIDGETSERVO)	+= misc/
-obj-$(CONFIG_USB_RIO500)	+= misc/
-obj-$(CONFIG_USB_SISUSBVGA)	+= misc/
-obj-$(CONFIG_USB_TEST)		+= misc/
-obj-$(CONFIG_USB_TRANCEVIBRATOR)+= misc/
-obj-$(CONFIG_USB_USS720)	+= misc/
-obj-$(CONFIG_USB_IOWARRIOR)	+= misc/
+obj-$(CONFIG_USB)		+= misc/
 
 obj-$(CONFIG_USB_ATM)		+= atm/
 obj-$(CONFIG_USB_SPEEDTOUCH)	+= atm/
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c
index a73e714..a51eeed 100644
--- a/drivers/usb/atm/cxacru.c
+++ b/drivers/usb/atm/cxacru.c
@@ -482,7 +482,9 @@
 	int rbuflen = ((rsize - 1) / stride + 1) * CMD_PACKET_SIZE;
 
 	if (wbuflen > PAGE_SIZE || rbuflen > PAGE_SIZE) {
-		dbg("too big transfer requested");
+		if (printk_ratelimit())
+			usb_err(instance->usbatm, "requested transfer size too large (%d, %d)\n",
+				wbuflen, rbuflen);
 		ret = -ENOMEM;
 		goto fail;
 	}
@@ -493,8 +495,9 @@
 	init_completion(&instance->rcv_done);
 	ret = usb_submit_urb(instance->rcv_urb, GFP_KERNEL);
 	if (ret < 0) {
-		dbg("submitting read urb for cm %#x failed", cm);
-		ret = ret;
+		if (printk_ratelimit())
+			usb_err(instance->usbatm, "submit of read urb for cm %#x failed (%d)\n",
+				cm, ret);
 		goto fail;
 	}
 
@@ -510,27 +513,29 @@
 	init_completion(&instance->snd_done);
 	ret = usb_submit_urb(instance->snd_urb, GFP_KERNEL);
 	if (ret < 0) {
-		dbg("submitting write urb for cm %#x failed", cm);
-		ret = ret;
+		if (printk_ratelimit())
+			usb_err(instance->usbatm, "submit of write urb for cm %#x failed (%d)\n",
+				cm, ret);
 		goto fail;
 	}
 
 	ret = cxacru_start_wait_urb(instance->snd_urb, &instance->snd_done, NULL);
 	if (ret < 0) {
-		dbg("sending cm %#x failed", cm);
-		ret = ret;
+		if (printk_ratelimit())
+			usb_err(instance->usbatm, "send of cm %#x failed (%d)\n", cm, ret);
 		goto fail;
 	}
 
 	ret = cxacru_start_wait_urb(instance->rcv_urb, &instance->rcv_done, &actlen);
 	if (ret < 0) {
-		dbg("receiving cm %#x failed", cm);
-		ret = ret;
+		if (printk_ratelimit())
+			usb_err(instance->usbatm, "receive of cm %#x failed (%d)\n", cm, ret);
 		goto fail;
 	}
 	if (actlen % CMD_PACKET_SIZE || !actlen) {
-		dbg("response is not a positive multiple of %d: %#x",
-				CMD_PACKET_SIZE, actlen);
+		if (printk_ratelimit())
+			usb_err(instance->usbatm, "invalid response length to cm %#x: %d\n",
+				cm, actlen);
 		ret = -EIO;
 		goto fail;
 	}
@@ -538,12 +543,16 @@
 	/* check the return status and copy the data to the output buffer, if needed */
 	for (offb = offd = 0; offd < rsize && offb < actlen; offb += CMD_PACKET_SIZE) {
 		if (rbuf[offb] != cm) {
-			dbg("wrong cm %#x in response", rbuf[offb]);
+			if (printk_ratelimit())
+				usb_err(instance->usbatm, "wrong cm %#x in response to cm %#x\n",
+					rbuf[offb], cm);
 			ret = -EIO;
 			goto fail;
 		}
 		if (rbuf[offb + 1] != CM_STATUS_SUCCESS) {
-			dbg("response failed: %#x", rbuf[offb + 1]);
+			if (printk_ratelimit())
+				usb_err(instance->usbatm, "response to cm %#x failed: %#x\n",
+					cm, rbuf[offb + 1]);
 			ret = -EIO;
 			goto fail;
 		}
@@ -582,14 +591,18 @@
 	for (offb = 0; offb < len; ) {
 		int l = le32_to_cpu(buf[offb++]);
 		if (l > stride || l > (len - offb) / 2) {
-			dbg("wrong data length %#x in response", l);
+			if (printk_ratelimit())
+				usb_err(instance->usbatm, "invalid data length from cm %#x: %d\n",
+					cm, l);
 			ret = -EIO;
 			goto cleanup;
 		}
 		while (l--) {
 			offd = le32_to_cpu(buf[offb++]);
 			if (offd >= size) {
-				dbg("wrong index %#x in response", offd);
+				if (printk_ratelimit())
+					usb_err(instance->usbatm, "wrong index #%x in response to cm #%x\n",
+						offd, cm);
 				ret = -EIO;
 				goto cleanup;
 			}
diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c
index eb0615a..8b132c4 100644
--- a/drivers/usb/atm/speedtch.c
+++ b/drivers/usb/atm/speedtch.c
@@ -251,7 +251,6 @@
 {
 	unsigned char *buffer;
 	struct usbatm_data *usbatm = instance->usbatm;
-	struct usb_interface *intf;
 	struct usb_device *usb_dev = usbatm->usb_dev;
 	int actual_length;
 	int ret = 0;
@@ -265,7 +264,7 @@
 		goto out;
 	}
 
-	if (!(intf = usb_ifnum_to_if(usb_dev, 2))) {
+	if (!usb_ifnum_to_if(usb_dev, 2)) {
 		ret = -ENODEV;
 		usb_dbg(usbatm, "%s: interface not found!\n", __func__);
 		goto out_free;
diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
index 29807d0..389c5b1 100644
--- a/drivers/usb/atm/ueagle-atm.c
+++ b/drivers/usb/atm/ueagle-atm.c
@@ -2,7 +2,8 @@
  * Copyright (c) 2003, 2004
  *	Damien Bergamini <damien.bergamini@free.fr>. All rights reserved.
  *
- * Copyright (c) 2005 Matthieu Castet <castet.matthieu@free.fr>
+ * Copyright (c) 2005-2007 Matthieu Castet <castet.matthieu@free.fr>
+ * Copyright (c) 2005-2007 Stanislaw Gruszka <stf_xl@wp.pl>
  *
  * 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
@@ -107,18 +108,51 @@
 #define uea_info(usb_dev, format,args...) \
 	dev_info(&(usb_dev)->dev ,"[ueagle-atm] " format, ##args)
 
-struct uea_cmvs {
+struct intr_pkt;
+
+/* cmv's from firmware */
+struct uea_cmvs_v1 {
 	u32 address;
 	u16 offset;
 	u32 data;
 } __attribute__ ((packed));
 
+struct uea_cmvs_v2 {
+	u32 group;
+	u32 address;
+	u32 offset;
+	u32 data;
+} __attribute__ ((packed));
+
+/* information about currently processed cmv */
+struct cmv_dsc_e1 {
+	u8 function;
+	u16 idx;
+	u32 address;
+	u16 offset;
+};
+
+struct cmv_dsc_e4 {
+	u16 function;
+	u16 offset;
+	u16 address;
+	u16 group;
+};
+
+union cmv_dsc {
+	struct cmv_dsc_e1 e1;
+	struct cmv_dsc_e4 e4;
+};
+
 struct uea_softc {
 	struct usb_device *usb_dev;
 	struct usbatm_data *usbatm;
 
 	int modem_index;
 	unsigned int driver_info;
+	int annex;
+#define ANNEXA 0
+#define ANNEXB 1
 
 	int booting;
 	int reset;
@@ -127,20 +161,23 @@
 
 	struct task_struct *kthread;
 	u32 data;
-	wait_queue_head_t cmv_ack_wait;
+	u32 data1;
+
 	int cmv_ack;
+	union cmv_dsc cmv_dsc;
 
 	struct work_struct task;
+	struct workqueue_struct *work_q;
 	u16 pageno;
 	u16 ovl;
 
 	const struct firmware *dsp_firm;
 	struct urb *urb_int;
 
-	u8 cmv_function;
-	u16 cmv_idx;
-	u32 cmv_address;
-	u16 cmv_offset;
+	void (*dispatch_cmv) (struct uea_softc *, struct intr_pkt *);
+	void (*schedule_load_page) (struct uea_softc *, struct intr_pkt *);
+	int (*stat) (struct uea_softc *);
+	int (*send_cmvs) (struct uea_softc *);
 
 	/* keep in sync with eaglectl */
 	struct uea_stats {
@@ -174,10 +211,34 @@
 #define ELSA_PID_PSTFIRM	0x3350
 #define ELSA_PID_PREFIRM	0x3351
 
+#define ELSA_PID_A_PREFIRM	0x3352
+#define ELSA_PID_A_PSTFIRM	0x3353
+#define ELSA_PID_B_PREFIRM	0x3362
+#define ELSA_PID_B_PSTFIRM	0x3363
+
 /*
- * Sagem USB IDs
+ * Devolo IDs : pots if (pid & 0x10)
  */
-#define EAGLE_VID		0x1110
+#define DEVOLO_VID			0x1039
+#define DEVOLO_EAGLE_I_A_PID_PSTFIRM	0x2110
+#define DEVOLO_EAGLE_I_A_PID_PREFIRM	0x2111
+
+#define DEVOLO_EAGLE_I_B_PID_PSTFIRM	0x2100
+#define DEVOLO_EAGLE_I_B_PID_PREFIRM	0x2101
+
+#define DEVOLO_EAGLE_II_A_PID_PSTFIRM	0x2130
+#define DEVOLO_EAGLE_II_A_PID_PREFIRM	0x2131
+
+#define DEVOLO_EAGLE_II_B_PID_PSTFIRM	0x2120
+#define DEVOLO_EAGLE_II_B_PID_PREFIRM	0x2121
+
+/*
+ * Reference design USB IDs
+ */
+#define ANALOG_VID		0x1110
+#define ADI930_PID_PREFIRM	0x9001
+#define ADI930_PID_PSTFIRM	0x9000
+
 #define EAGLE_I_PID_PREFIRM	0x9010	/* Eagle I */
 #define EAGLE_I_PID_PSTFIRM	0x900F	/* Eagle I */
 
@@ -187,12 +248,12 @@
 #define EAGLE_II_PID_PREFIRM	0x9022	/* Eagle II */
 #define EAGLE_II_PID_PSTFIRM	0x9021	/* Eagle II */
 
-/*
- *  Eagle III Pid
- */
 #define EAGLE_III_PID_PREFIRM	0x9032	/* Eagle III */
 #define EAGLE_III_PID_PSTFIRM	0x9031	/* Eagle III */
 
+#define EAGLE_IV_PID_PREFIRM	0x9042  /* Eagle IV */
+#define EAGLE_IV_PID_PSTFIRM	0x9041  /* Eagle IV */
+
 /*
  * USR USB IDs
  */
@@ -208,11 +269,15 @@
 
 #define PREFIRM 0
 #define PSTFIRM (1<<7)
+#define AUTO_ANNEX_A (1<<8)
+#define AUTO_ANNEX_B (1<<9)
+
 enum {
 	ADI930 = 0,
 	EAGLE_I,
 	EAGLE_II,
-	EAGLE_III
+	EAGLE_III,
+	EAGLE_IV
 };
 
 /* macros for both struct usb_device_id and struct uea_softc */
@@ -221,15 +286,18 @@
 #define UEA_CHIP_VERSION(x) \
 	((x)->driver_info & 0xf)
 
-#define IS_ISDN(usb_dev) \
-	(le16_to_cpu((usb_dev)->descriptor.bcdDevice) & 0x80)
+#define IS_ISDN(x) \
+	((x)->annex & ANNEXB)
 
 #define INS_TO_USBDEV(ins) ins->usb_dev
 
 #define GET_STATUS(data) \
 	((data >> 8) & 0xf)
+
 #define IS_OPERATIONAL(sc) \
-	(GET_STATUS(sc->stats.phy.state) == 2)
+	((UEA_CHIP_VERSION(sc) != EAGLE_IV) ? \
+	(GET_STATUS(sc->stats.phy.state) == 2) : \
+	(sc->stats.phy.state == 7))
 
 /*
  * Set of macros to handle unaligned data in the firmware blob.
@@ -259,7 +327,8 @@
 #define UEA_INTR_PIPE		0x04
 #define UEA_ISO_DATA_PIPE	0x08
 
-#define UEA_SET_BLOCK    	0x0001
+#define UEA_E1_SET_BLOCK    	0x0001
+#define UEA_E4_SET_BLOCK	0x002c
 #define UEA_SET_MODE     	0x0003
 #define UEA_SET_2183_DATA	0x0004
 #define UEA_SET_TIMEOUT		0x0011
@@ -275,71 +344,179 @@
 #define UEA_MPTX_MAILBOX	(0x3fd6 | 0x4000)
 #define UEA_MPRX_MAILBOX	(0x3fdf | 0x4000)
 
-/* structure describing a block within a DSP page */
-struct block_info {
+/* block information in eagle4 dsp firmware  */
+struct block_index {
+	__le32 PageOffset;
+	__le32 NotLastBlock;
+	__le32 dummy;
+	__le32 PageSize;
+	__le32 PageAddress;
+	__le16 dummy1;
+	__le16 PageNumber;
+} __attribute__ ((packed));
+
+#define E4_IS_BOOT_PAGE(PageSize) ((le32_to_cpu(PageSize)) & 0x80000000)
+#define E4_PAGE_BYTES(PageSize) ((le32_to_cpu(PageSize) & 0x7fffffff) * 4)
+
+#define E4_L1_STRING_HEADER 0x10
+#define E4_MAX_PAGE_NUMBER 0x58
+#define E4_NO_SWAPPAGE_HEADERS 0x31
+
+/* l1_code is eagle4 dsp firmware format */
+struct l1_code {
+	u8 string_header[E4_L1_STRING_HEADER];
+	u8 page_number_to_block_index[E4_MAX_PAGE_NUMBER];
+	struct block_index page_header[E4_NO_SWAPPAGE_HEADERS];
+	u8 code [0];
+} __attribute__ ((packed));
+
+/* structures describing a block within a DSP page */
+struct block_info_e1 {
 	__le16 wHdr;
-#define UEA_BIHDR 0xabcd
 	__le16 wAddress;
 	__le16 wSize;
 	__le16 wOvlOffset;
 	__le16 wOvl;		/* overlay */
 	__le16 wLast;
 } __attribute__ ((packed));
-#define BLOCK_INFO_SIZE 12
+#define E1_BLOCK_INFO_SIZE 12
 
-/* structure representing a CMV (Configuration and Management Variable) */
-struct cmv {
-	__le16 wPreamble;
-#define PREAMBLE 0x535c
-	__u8 bDirection;
-#define MODEMTOHOST 0x01
-#define HOSTTOMODEM 0x10
-	__u8 bFunction;
-#define FUNCTION_TYPE(f)    ((f) >> 4)
-#define MEMACCESS	0x1
-#define ADSLDIRECTIVE	0x7
+struct block_info_e4 {
+	__be16 wHdr;
+	__u8 bBootPage;
+	__u8 bPageNumber;
+	__be32 dwSize;
+	__be32 dwAddress;
+	__be16 wReserved;
+} __attribute__ ((packed));
+#define E4_BLOCK_INFO_SIZE 14
 
-#define FUNCTION_SUBTYPE(f) ((f) & 0x0f)
+#define UEA_BIHDR 0xabcd
+#define UEA_RESERVED 0xffff
+
+/* constants describing cmv type */
+#define E1_PREAMBLE 0x535c
+#define E1_MODEMTOHOST 0x01
+#define E1_HOSTTOMODEM 0x10
+
+#define E1_MEMACCESS 0x1
+#define E1_ADSLDIRECTIVE 0x7
+#define E1_FUNCTION_TYPE(f) ((f) >> 4)
+#define E1_FUNCTION_SUBTYPE(f) ((f) & 0x0f)
+
+#define E4_MEMACCESS 0
+#define E4_ADSLDIRECTIVE 0xf
+#define E4_FUNCTION_TYPE(f) ((f) >> 8)
+#define E4_FUNCTION_SIZE(f) ((f) & 0x0f)
+#define E4_FUNCTION_SUBTYPE(f) (((f) >> 4) & 0x0f)
+
 /* for MEMACCESS */
-#define REQUESTREAD	0x0
-#define REQUESTWRITE	0x1
-#define REPLYREAD	0x2
-#define REPLYWRITE	0x3
-/* for ADSLDIRECTIVE */
-#define KERNELREADY	0x0
-#define MODEMREADY	0x1
+#define E1_REQUESTREAD	0x0
+#define E1_REQUESTWRITE	0x1
+#define E1_REPLYREAD	0x2
+#define E1_REPLYWRITE	0x3
 
-#define MAKEFUNCTION(t, s) (((t) & 0xf) << 4 | ((s) & 0xf))
-	__le16 wIndex;
-	__le32 dwSymbolicAddress;
-#define MAKESA(a, b, c, d)						\
+#define E4_REQUESTREAD	0x0
+#define E4_REQUESTWRITE	0x4
+#define E4_REPLYREAD	(E4_REQUESTREAD | 1)
+#define E4_REPLYWRITE	(E4_REQUESTWRITE | 1)
+
+/* for ADSLDIRECTIVE */
+#define E1_KERNELREADY 0x0
+#define E1_MODEMREADY  0x1
+
+#define E4_KERNELREADY 0x0
+#define E4_MODEMREADY  0x1
+
+#define E1_MAKEFUNCTION(t, s) (((t) & 0xf) << 4 | ((s) & 0xf))
+#define E4_MAKEFUNCTION(t, st, s) (((t) & 0xf) << 8 | ((st) & 0xf) << 4 | ((s) & 0xf))
+
+#define E1_MAKESA(a, b, c, d)						\
 	(((c) & 0xff) << 24 |						\
 	 ((d) & 0xff) << 16 |						\
 	 ((a) & 0xff) << 8  |						\
 	 ((b) & 0xff))
-#define GETSA1(a) ((a >> 8) & 0xff)
-#define GETSA2(a) (a & 0xff)
-#define GETSA3(a) ((a >> 24) & 0xff)
-#define GETSA4(a) ((a >> 16) & 0xff)
 
-#define SA_CNTL MAKESA('C', 'N', 'T', 'L')
-#define SA_DIAG MAKESA('D', 'I', 'A', 'G')
-#define SA_INFO MAKESA('I', 'N', 'F', 'O')
-#define SA_OPTN MAKESA('O', 'P', 'T', 'N')
-#define SA_RATE MAKESA('R', 'A', 'T', 'E')
-#define SA_STAT MAKESA('S', 'T', 'A', 'T')
+#define E1_GETSA1(a) ((a >> 8) & 0xff)
+#define E1_GETSA2(a) (a & 0xff)
+#define E1_GETSA3(a) ((a >> 24) & 0xff)
+#define E1_GETSA4(a) ((a >> 16) & 0xff)
+
+#define E1_SA_CNTL E1_MAKESA('C', 'N', 'T', 'L')
+#define E1_SA_DIAG E1_MAKESA('D', 'I', 'A', 'G')
+#define E1_SA_INFO E1_MAKESA('I', 'N', 'F', 'O')
+#define E1_SA_OPTN E1_MAKESA('O', 'P', 'T', 'N')
+#define E1_SA_RATE E1_MAKESA('R', 'A', 'T', 'E')
+#define E1_SA_STAT E1_MAKESA('S', 'T', 'A', 'T')
+
+#define E4_SA_CNTL 1
+#define E4_SA_STAT 2
+#define E4_SA_INFO 3
+#define E4_SA_TEST 4
+#define E4_SA_OPTN 5
+#define E4_SA_RATE 6
+#define E4_SA_DIAG 7
+#define E4_SA_CNFG 8
+
+/* structures representing a CMV (Configuration and Management Variable) */
+struct cmv_e1 {
+	__le16 wPreamble;
+	__u8 bDirection;
+	__u8 bFunction;
+	__le16 wIndex;
+	__le32 dwSymbolicAddress;
 	__le16 wOffsetAddress;
 	__le32 dwData;
 } __attribute__ ((packed));
-#define CMV_SIZE 16
 
-/* structure representing swap information */
-struct swap_info {
+struct cmv_e4 {
+	__be16 wGroup;
+	__be16 wFunction;
+	__be16 wOffset;
+	__be16 wAddress;
+	__be32 dwData [6];
+} __attribute__ ((packed));
+
+/* structures representing swap information */
+struct swap_info_e1 {
 	__u8 bSwapPageNo;
 	__u8 bOvl;		/* overlay */
 } __attribute__ ((packed));
 
-/* structure representing interrupt data */
+struct swap_info_e4 {
+	__u8 bSwapPageNo;
+} __attribute__ ((packed));
+
+/* structures representing interrupt data */
+#define e1_bSwapPageNo	u.e1.s1.swapinfo.bSwapPageNo
+#define e1_bOvl		u.e1.s1.swapinfo.bOvl
+#define e4_bSwapPageNo  u.e4.s1.swapinfo.bSwapPageNo
+
+#define INT_LOADSWAPPAGE 0x0001
+#define INT_INCOMINGCMV  0x0002
+
+union intr_data_e1 {
+	struct {
+		struct swap_info_e1 swapinfo;
+		__le16 wDataSize;
+	} __attribute__ ((packed)) s1;
+	struct {
+		struct cmv_e1 cmv;
+		__le16 wDataSize;
+	} __attribute__ ((packed)) s2;
+} __attribute__ ((packed));
+
+union intr_data_e4 {
+	struct {
+		struct swap_info_e4 swapinfo;
+		__le16 wDataSize;
+	} __attribute__ ((packed)) s1;
+	struct {
+		struct cmv_e4 cmv;
+		__le16 wDataSize;
+	} __attribute__ ((packed)) s2;
+} __attribute__ ((packed));
+
 struct intr_pkt {
 	__u8 bType;
 	__u8 bNotification;
@@ -347,43 +524,48 @@
 	__le16 wIndex;
 	__le16 wLength;
 	__le16 wInterrupt;
-#define INT_LOADSWAPPAGE 0x0001
-#define INT_INCOMINGCMV  0x0002
 	union {
-		struct {
-			struct swap_info swapinfo;
-			__le16 wDataSize;
-		} __attribute__ ((packed)) s1;
-
-		struct {
-			struct cmv cmv;
-			__le16 wDataSize;
-		} __attribute__ ((packed)) s2;
-	} __attribute__ ((packed)) u;
-#define bSwapPageNo	u.s1.swapinfo.bSwapPageNo
-#define bOvl		u.s1.swapinfo.bOvl
+		union intr_data_e1 e1;
+		union intr_data_e4 e4;
+	} u;
 } __attribute__ ((packed));
-#define INTR_PKT_SIZE 28
+
+#define E1_INTR_PKT_SIZE 28
+#define E4_INTR_PKT_SIZE 64
 
 static struct usb_driver uea_driver;
 static DEFINE_MUTEX(uea_mutex);
-static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III"};
+static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III", "Eagle IV"};
 
 static int modem_index;
 static unsigned int debug;
-static int use_iso[NB_MODEM] = {[0 ... (NB_MODEM - 1)] = 1};
+static unsigned int altsetting[NB_MODEM] = {[0 ... (NB_MODEM - 1)] = FASTEST_ISO_INTF};
 static int sync_wait[NB_MODEM];
 static char *cmv_file[NB_MODEM];
+static int annex[NB_MODEM];
 
 module_param(debug, uint, 0644);
 MODULE_PARM_DESC(debug, "module debug level (0=off,1=on,2=verbose)");
-module_param_array(use_iso, bool, NULL, 0644);
-MODULE_PARM_DESC(use_iso, "use isochronous usb pipe for incoming traffic");
+module_param_array(altsetting, uint, NULL, 0644);
+MODULE_PARM_DESC(altsetting, "alternate setting for incoming traffic: 0=bulk, "
+			     "1=isoc slowest, ... , 8=isoc fastest (default)");
 module_param_array(sync_wait, bool, NULL, 0644);
 MODULE_PARM_DESC(sync_wait, "wait the synchronisation before starting ATM");
 module_param_array(cmv_file, charp, NULL, 0644);
 MODULE_PARM_DESC(cmv_file,
 		"file name with configuration and management variables");
+module_param_array(annex, uint, NULL, 0644);
+MODULE_PARM_DESC(annex,
+                 "manually set annex a/b (0=auto, 1=annex a, 2=annex b)");
+
+#define uea_wait(sc, cond, timeo) \
+({ \
+	int _r = wait_event_interruptible_timeout(sc->sync_q, \
+			(cond) || kthread_should_stop(), timeo); \
+	if (kthread_should_stop()) \
+		_r = -ENODEV; \
+	_r; \
+})
 
 #define UPDATE_ATM_STAT(type, val) \
 	do { \
@@ -519,6 +701,9 @@
 	case EAGLE_III:
 		fw_name = FW_DIR "eagleIII.fw";
 		break;
+	case EAGLE_IV:
+		fw_name = FW_DIR "eagleIV.fw";
+		break;
 	}
 
 	ret = request_firmware_nowait(THIS_MODULE, 1, fw_name, &usb->dev, usb, uea_upload_pre_firmware);
@@ -537,7 +722,7 @@
 /*
  * Make sure that the DSP code provided is safe to use.
  */
-static int check_dsp(u8 *dsp, unsigned int len)
+static int check_dsp_e1(u8 *dsp, unsigned int len)
 {
 	u8 pagecount, blockcount;
 	u16 blocksize;
@@ -588,6 +773,51 @@
 	return 0;
 }
 
+static int check_dsp_e4(u8 *dsp, int len)
+{
+	int i;
+	struct l1_code *p = (struct l1_code *) dsp;
+	unsigned int sum = p->code - dsp;
+
+	if (len < sum)
+		return 1;
+
+	if (strcmp("STRATIPHY ANEXA", p->string_header) != 0 &&
+	    strcmp("STRATIPHY ANEXB", p->string_header) != 0)
+		return 1;
+
+	for (i = 0; i < E4_MAX_PAGE_NUMBER; i++) {
+		struct block_index *blockidx;
+		u8 blockno = p->page_number_to_block_index[i];
+		if (blockno >= E4_NO_SWAPPAGE_HEADERS)
+			continue;
+
+		do {
+			u64 l;
+
+			if (blockno >= E4_NO_SWAPPAGE_HEADERS)
+				return 1;
+
+			blockidx = &p->page_header[blockno++];
+			if ((u8 *)(blockidx + 1) - dsp  >= len)
+				return 1;
+
+			if (le16_to_cpu(blockidx->PageNumber) != i)
+				return 1;
+
+			l = E4_PAGE_BYTES(blockidx->PageSize);
+			sum += l;
+			l += le32_to_cpu(blockidx->PageOffset);
+			if (l > len)
+				return 1;
+
+		/* zero is zero regardless endianes */
+		} while (blockidx->NotLastBlock);
+	}
+
+	return (sum == len) ? 0 : 1;
+}
+
 /*
  * send data to the idma pipe
  * */
@@ -624,13 +854,18 @@
 	int ret;
 	char *dsp_name;
 
-	if (UEA_CHIP_VERSION(sc) == ADI930) {
-		if (IS_ISDN(sc->usb_dev))
+	if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
+		if (IS_ISDN(sc))
+			dsp_name = FW_DIR "DSP4i.bin";
+		else
+			dsp_name = FW_DIR "DSP4p.bin";
+	} else if (UEA_CHIP_VERSION(sc) == ADI930) {
+		if (IS_ISDN(sc))
 			dsp_name = FW_DIR "DSP9i.bin";
 		else
 			dsp_name = FW_DIR "DSP9p.bin";
 	} else {
-		if (IS_ISDN(sc->usb_dev))
+		if (IS_ISDN(sc))
 			dsp_name = FW_DIR "DSPei.bin";
 		else
 			dsp_name = FW_DIR "DSPep.bin";
@@ -640,11 +875,16 @@
 	if (ret < 0) {
 		uea_err(INS_TO_USBDEV(sc),
 		       "requesting firmware %s failed with error %d\n",
-		       dsp_name, ret);
+		        dsp_name, ret);
 		return ret;
 	}
 
-	if (check_dsp(sc->dsp_firm->data, sc->dsp_firm->size)) {
+	if (UEA_CHIP_VERSION(sc) == EAGLE_IV)
+		ret = check_dsp_e4(sc->dsp_firm->data, sc->dsp_firm->size);
+	else
+		ret = check_dsp_e1(sc->dsp_firm->data, sc->dsp_firm->size);
+
+	if (ret) {
 		uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n",
 		       dsp_name);
 		release_firmware(sc->dsp_firm);
@@ -658,12 +898,12 @@
 /*
  * The uea_load_page() function must be called within a process context
  */
-static void uea_load_page(struct work_struct *work)
+static void uea_load_page_e1(struct work_struct *work)
 {
 	struct uea_softc *sc = container_of(work, struct uea_softc, task);
 	u16 pageno = sc->pageno;
 	u16 ovl = sc->ovl;
-	struct block_info bi;
+	struct block_info_e1 bi;
 
 	u8 *p;
 	u8 pagecount, blockcount;
@@ -716,7 +956,7 @@
 		bi.wLast = cpu_to_le16((i == blockcount - 1) ? 1 : 0);
 
 		/* send block info through the IDMA pipe */
-		if (uea_idma_write(sc, &bi, BLOCK_INFO_SIZE))
+		if (uea_idma_write(sc, &bi, E1_BLOCK_INFO_SIZE))
 			goto bad2;
 
 		/* send block data through the IDMA pipe */
@@ -735,17 +975,114 @@
 	uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno);
 }
 
+static void __uea_load_page_e4(struct uea_softc *sc, u8 pageno, int boot)
+{
+	struct block_info_e4 bi;
+	struct block_index *blockidx;
+	struct l1_code *p = (struct l1_code *) sc->dsp_firm->data;
+	u8 blockno = p->page_number_to_block_index[pageno];
+
+	bi.wHdr = cpu_to_be16(UEA_BIHDR);
+	bi.bBootPage = boot;
+	bi.bPageNumber = pageno;
+	bi.wReserved = cpu_to_be16(UEA_RESERVED);
+
+	do {
+		u8 *blockoffset;
+		unsigned int blocksize;
+
+		blockidx = &p->page_header[blockno];
+		blocksize = E4_PAGE_BYTES(blockidx->PageSize);
+		blockoffset = sc->dsp_firm->data + le32_to_cpu(blockidx->PageOffset);
+
+		bi.dwSize = cpu_to_be32(blocksize);
+		bi.dwAddress = swab32(blockidx->PageAddress);
+
+		uea_dbg(INS_TO_USBDEV(sc),
+		       "sending block %u for DSP page %u size %u adress %x\n",
+		       blockno, pageno, blocksize, le32_to_cpu(blockidx->PageAddress));
+
+		/* send block info through the IDMA pipe */
+		if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE))
+			goto bad;
+
+		/* send block data through the IDMA pipe */
+		if (uea_idma_write(sc, blockoffset, blocksize))
+			goto bad;
+
+		blockno++;
+	} while (blockidx->NotLastBlock);
+
+	return;
+
+bad:
+	uea_err(INS_TO_USBDEV(sc), "sending DSP block %u failed\n", blockno);
+	return;
+}
+
+static void uea_load_page_e4(struct work_struct *work)
+{
+	struct uea_softc *sc = container_of(work, struct uea_softc, task);
+	u8 pageno = sc->pageno;
+	int i;
+	struct block_info_e4 bi;
+	struct l1_code *p;
+
+	uea_dbg(INS_TO_USBDEV(sc), "sending DSP page %u\n", pageno);
+
+	/* reload firmware when reboot start and it's loaded already */
+	if (pageno == 0 && sc->dsp_firm) {
+		release_firmware(sc->dsp_firm);
+		sc->dsp_firm = NULL;
+	}
+
+	if (sc->dsp_firm == NULL && request_dsp(sc) < 0)
+		return;
+
+	p = (struct l1_code *) sc->dsp_firm->data;
+	if (pageno >= p->page_header[0].PageNumber) {
+		uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno);
+		return;
+	}
+
+	if (pageno != 0) {
+		__uea_load_page_e4(sc, pageno, 0);
+		return;
+	}
+
+	uea_dbg(INS_TO_USBDEV(sc),
+	       "sending Main DSP page %u\n", p->page_header[0].PageNumber);
+
+	for (i = 0; i < le16_to_cpu(p->page_header[0].PageNumber); i++) {
+		if (E4_IS_BOOT_PAGE(p->page_header[i].PageSize))
+			__uea_load_page_e4(sc, i, 1);
+	}
+
+	uea_dbg(INS_TO_USBDEV(sc),"sending start bi\n");
+
+	bi.wHdr = cpu_to_be16(UEA_BIHDR);
+	bi.bBootPage = 0;
+	bi.bPageNumber = 0xff;
+	bi.wReserved = cpu_to_be16(UEA_RESERVED);
+	bi.dwSize = cpu_to_be32(E4_PAGE_BYTES(p->page_header[0].PageSize));
+	bi.dwAddress = swab32(p->page_header[0].PageAddress);
+
+	/* send block info through the IDMA pipe */
+	if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE))
+		uea_err(INS_TO_USBDEV(sc), "sending DSP start bi failed\n");
+}
+
 static inline void wake_up_cmv_ack(struct uea_softc *sc)
 {
 	BUG_ON(sc->cmv_ack);
 	sc->cmv_ack = 1;
-	wake_up(&sc->cmv_ack_wait);
+	wake_up(&sc->sync_q);
 }
 
 static inline int wait_cmv_ack(struct uea_softc *sc)
 {
-	int ret = wait_event_interruptible_timeout(sc->cmv_ack_wait,
-						   sc->cmv_ack, ACK_TIMEOUT);
+	int ret = uea_wait(sc, sc->cmv_ack , ACK_TIMEOUT);
+
 	sc->cmv_ack = 0;
 
 	uea_dbg(INS_TO_USBDEV(sc), "wait_event_timeout : %d ms\n",
@@ -792,33 +1129,34 @@
 	return 0;
 }
 
-static int uea_cmv(struct uea_softc *sc,
+static int uea_cmv_e1(struct uea_softc *sc,
 		u8 function, u32 address, u16 offset, u32 data)
 {
-	struct cmv cmv;
+	struct cmv_e1 cmv;
 	int ret;
 
 	uea_enters(INS_TO_USBDEV(sc));
 	uea_vdbg(INS_TO_USBDEV(sc), "Function : %d-%d, Address : %c%c%c%c, "
 			"offset : 0x%04x, data : 0x%08x\n",
-			FUNCTION_TYPE(function), FUNCTION_SUBTYPE(function),
-			GETSA1(address), GETSA2(address), GETSA3(address),
-			GETSA4(address), offset, data);
-	/* we send a request, but we expect a reply */
-	sc->cmv_function = function | 0x2;
-	sc->cmv_idx++;
-	sc->cmv_address = address;
-	sc->cmv_offset = offset;
+			E1_FUNCTION_TYPE(function), E1_FUNCTION_SUBTYPE(function),
+			E1_GETSA1(address), E1_GETSA2(address), E1_GETSA3(address),
+			E1_GETSA4(address), offset, data);
 
-	cmv.wPreamble = cpu_to_le16(PREAMBLE);
-	cmv.bDirection = HOSTTOMODEM;
+	/* we send a request, but we expect a reply */
+	sc->cmv_dsc.e1.function = function | 0x2;
+	sc->cmv_dsc.e1.idx++;
+	sc->cmv_dsc.e1.address = address;
+	sc->cmv_dsc.e1.offset = offset;
+
+	cmv.wPreamble = cpu_to_le16(E1_PREAMBLE);
+	cmv.bDirection = E1_HOSTTOMODEM;
 	cmv.bFunction = function;
-	cmv.wIndex = cpu_to_le16(sc->cmv_idx);
+	cmv.wIndex = cpu_to_le16(sc->cmv_dsc.e1.idx);
 	put_unaligned(cpu_to_le32(address), &cmv.dwSymbolicAddress);
 	cmv.wOffsetAddress = cpu_to_le16(offset);
 	put_unaligned(cpu_to_le32(data >> 16 | data << 16), &cmv.dwData);
 
-	ret = uea_request(sc, UEA_SET_BLOCK, UEA_MPTX_START, CMV_SIZE, &cmv);
+	ret = uea_request(sc, UEA_E1_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv);
 	if (ret < 0)
 		return ret;
 	ret = wait_cmv_ack(sc);
@@ -826,10 +1164,44 @@
 	return ret;
 }
 
-static inline int uea_read_cmv(struct uea_softc *sc,
+static int uea_cmv_e4(struct uea_softc *sc,
+		u16 function, u16 group, u16 address, u16 offset, u32 data)
+{
+	struct cmv_e4 cmv;
+	int ret;
+
+	uea_enters(INS_TO_USBDEV(sc));
+	memset(&cmv, 0, sizeof(cmv));
+
+	uea_vdbg(INS_TO_USBDEV(sc), "Function : %d-%d, Group : 0x%04x, "
+		 "Address : 0x%04x, offset : 0x%04x, data : 0x%08x\n",
+		 E4_FUNCTION_TYPE(function), E4_FUNCTION_SUBTYPE(function),
+		 group, address, offset, data);
+
+	/* we send a request, but we expect a reply */
+	sc->cmv_dsc.e4.function = function | (0x1 << 4);
+	sc->cmv_dsc.e4.offset = offset;
+	sc->cmv_dsc.e4.address = address;
+	sc->cmv_dsc.e4.group = group;
+
+	cmv.wFunction = cpu_to_be16(function);
+	cmv.wGroup = cpu_to_be16(group);
+	cmv.wAddress = cpu_to_be16(address);
+	cmv.wOffset = cpu_to_be16(offset);
+	cmv.dwData[0] = cpu_to_be32(data);
+
+	ret = uea_request(sc, UEA_E4_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv);
+	if (ret < 0)
+		return ret;
+	ret = wait_cmv_ack(sc);
+	uea_leaves(INS_TO_USBDEV(sc));
+	return ret;
+}
+
+static inline int uea_read_cmv_e1(struct uea_softc *sc,
 		u32 address, u16 offset, u32 *data)
 {
-	int ret = uea_cmv(sc, MAKEFUNCTION(MEMACCESS, REQUESTREAD),
+	int ret = uea_cmv_e1(sc, E1_MAKEFUNCTION(E1_MEMACCESS, E1_REQUESTREAD),
 			  address, offset, 0);
 	if (ret < 0)
 		uea_err(INS_TO_USBDEV(sc),
@@ -840,10 +1212,27 @@
 	return ret;
 }
 
-static inline int uea_write_cmv(struct uea_softc *sc,
+static inline int uea_read_cmv_e4(struct uea_softc *sc,
+		u8 size, u16 group, u16 address, u16 offset, u32 *data)
+{
+	int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS, E4_REQUESTREAD, size),
+			  group, address, offset, 0);
+	if (ret < 0)
+		uea_err(INS_TO_USBDEV(sc),
+			"reading cmv failed with error %d\n", ret);
+	else {
+	 	*data = sc->data;
+		/* size is in 16-bit word quantities */
+		if (size > 2)
+			*(data + 1) = sc->data1;
+	}
+	return ret;
+}
+
+static inline int uea_write_cmv_e1(struct uea_softc *sc,
 		u32 address, u16 offset, u32 data)
 {
-	int ret = uea_cmv(sc, MAKEFUNCTION(MEMACCESS, REQUESTWRITE),
+	int ret = uea_cmv_e1(sc, E1_MAKEFUNCTION(E1_MEMACCESS, E1_REQUESTWRITE),
 			  address, offset, data);
 	if (ret < 0)
 		uea_err(INS_TO_USBDEV(sc),
@@ -852,12 +1241,48 @@
 	return ret;
 }
 
+static inline int uea_write_cmv_e4(struct uea_softc *sc,
+		u8 size, u16 group, u16 address, u16 offset, u32 data)
+{
+	int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS, E4_REQUESTWRITE, size),
+			  group, address, offset, data);
+	if (ret < 0)
+		uea_err(INS_TO_USBDEV(sc),
+			"writing cmv failed with error %d\n", ret);
+
+	return ret;
+}
+
+static void uea_set_bulk_timeout(struct uea_softc *sc, u32 dsrate)
+{
+	int ret;
+	u16 timeout;
+
+	/* in bulk mode the modem have problem with high rate
+	 * changing internal timing could improve things, but the
+	 * value is misterious.
+	 * ADI930 don't support it (-EPIPE error).
+	 */
+
+	if (UEA_CHIP_VERSION(sc) == ADI930 ||
+	    altsetting[sc->modem_index] > 0 ||
+	    sc->stats.phy.dsrate == dsrate)
+		return;
+
+	/* Original timming (1Mbit/s) from ADI (used in windows driver) */
+	timeout = (dsrate <= 1024*1024) ? 0 : 1;
+	ret = uea_request(sc, UEA_SET_TIMEOUT, timeout, 0, NULL);
+	uea_info(INS_TO_USBDEV(sc), "setting new timeout %d%s\n",
+		 timeout,  ret < 0 ? " failed" : "");
+
+}
+
 /*
  * Monitor the modem and update the stat
  * return 0 if everything is ok
  * return < 0 if an error occurs (-EAGAIN reboot needed)
  */
-static int uea_stat(struct uea_softc *sc)
+static int uea_stat_e1(struct uea_softc *sc)
 {
 	u32 data;
 	int ret;
@@ -865,7 +1290,7 @@
 	uea_enters(INS_TO_USBDEV(sc));
 	data = sc->stats.phy.state;
 
-	ret = uea_read_cmv(sc, SA_STAT, 0, &sc->stats.phy.state);
+	ret = uea_read_cmv_e1(sc, E1_SA_STAT, 0, &sc->stats.phy.state);
 	if (ret < 0)
 		return ret;
 
@@ -885,7 +1310,7 @@
 
 	case 3:		/* fail ... */
 		uea_info(INS_TO_USBDEV(sc), "modem synchronization failed"
-				" (may be try other cmv/dsp)\n");
+					" (may be try other cmv/dsp)\n");
 		return -EAGAIN;
 
 	case 4 ... 6:	/* test state */
@@ -923,7 +1348,7 @@
 	/* wake up processes waiting for synchronization */
 	wake_up(&sc->sync_q);
 
-	ret = uea_read_cmv(sc, SA_DIAG, 2, &sc->stats.phy.flags);
+	ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 2, &sc->stats.phy.flags);
 	if (ret < 0)
 		return ret;
 	sc->stats.phy.mflags |= sc->stats.phy.flags;
@@ -937,105 +1362,223 @@
 		return 0;
 	}
 
-	ret = uea_read_cmv(sc, SA_RATE, 0, &data);
+	ret = uea_read_cmv_e1(sc, E1_SA_RATE, 0, &data);
 	if (ret < 0)
 		return ret;
 
-	/* in bulk mode the modem have problem with high rate
-	 * changing internal timing could improve things, but the
-	 * value is misterious.
-	 * ADI930 don't support it (-EPIPE error).
-	 */
-	if (UEA_CHIP_VERSION(sc) != ADI930
-		    && !use_iso[sc->modem_index]
-		    && sc->stats.phy.dsrate != (data >> 16) * 32) {
-		/* Original timming from ADI(used in windows driver)
-		 * 0x20ffff>>16 * 32 = 32 * 32 = 1Mbits
-		 */
-		u16 timeout = (data <= 0x20ffff) ? 0 : 1;
-		ret = uea_request(sc, UEA_SET_TIMEOUT, timeout, 0, NULL);
-		uea_info(INS_TO_USBDEV(sc),
-				"setting new timeout %d%s\n", timeout,
-				ret < 0?" failed":"");
-	}
+	uea_set_bulk_timeout(sc, (data >> 16) * 32);
 	sc->stats.phy.dsrate = (data >> 16) * 32;
 	sc->stats.phy.usrate = (data & 0xffff) * 32;
 	UPDATE_ATM_STAT(link_rate, sc->stats.phy.dsrate * 1000 / 424);
 
-	ret = uea_read_cmv(sc, SA_DIAG, 23, &data);
+	ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 23, &data);
 	if (ret < 0)
 		return ret;
 	sc->stats.phy.dsattenuation = (data & 0xff) / 2;
 
-	ret = uea_read_cmv(sc, SA_DIAG, 47, &data);
+	ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 47, &data);
 	if (ret < 0)
 		return ret;
 	sc->stats.phy.usattenuation = (data & 0xff) / 2;
 
-	ret = uea_read_cmv(sc, SA_DIAG, 25, &sc->stats.phy.dsmargin);
+	ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 25, &sc->stats.phy.dsmargin);
 	if (ret < 0)
 		return ret;
 
-	ret = uea_read_cmv(sc, SA_DIAG, 49, &sc->stats.phy.usmargin);
+	ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 49, &sc->stats.phy.usmargin);
 	if (ret < 0)
 		return ret;
 
-	ret = uea_read_cmv(sc, SA_DIAG, 51, &sc->stats.phy.rxflow);
+	ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 51, &sc->stats.phy.rxflow);
 	if (ret < 0)
 		return ret;
 
-	ret = uea_read_cmv(sc, SA_DIAG, 52, &sc->stats.phy.txflow);
+	ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 52, &sc->stats.phy.txflow);
 	if (ret < 0)
 		return ret;
 
-	ret = uea_read_cmv(sc, SA_DIAG, 54, &sc->stats.phy.dsunc);
+	ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 54, &sc->stats.phy.dsunc);
 	if (ret < 0)
 		return ret;
 
 	/* only for atu-c */
-	ret = uea_read_cmv(sc, SA_DIAG, 58, &sc->stats.phy.usunc);
+	ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 58, &sc->stats.phy.usunc);
 	if (ret < 0)
 		return ret;
 
-	ret = uea_read_cmv(sc, SA_DIAG, 53, &sc->stats.phy.dscorr);
+	ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 53, &sc->stats.phy.dscorr);
 	if (ret < 0)
 		return ret;
 
 	/* only for atu-c */
-	ret = uea_read_cmv(sc, SA_DIAG, 57, &sc->stats.phy.uscorr);
+	ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 57, &sc->stats.phy.uscorr);
 	if (ret < 0)
 		return ret;
 
-	ret = uea_read_cmv(sc, SA_INFO, 8, &sc->stats.phy.vidco);
+	ret = uea_read_cmv_e1(sc, E1_SA_INFO, 8, &sc->stats.phy.vidco);
 	if (ret < 0)
 		return ret;
 
-	ret = uea_read_cmv(sc, SA_INFO, 13, &sc->stats.phy.vidcpe);
+	ret = uea_read_cmv_e1(sc, E1_SA_INFO, 13, &sc->stats.phy.vidcpe);
 	if (ret < 0)
 		return ret;
 
 	return 0;
 }
 
-static int request_cmvs(struct uea_softc *sc,
-		 struct uea_cmvs **cmvs, const struct firmware **fw)
+static int uea_stat_e4(struct uea_softc *sc)
 {
-	int ret, size;
-	u8 *data;
-	char *file;
-	char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */
+	u32 data;
+	u32 tmp_arr[2];
+	int ret;
 
+	uea_enters(INS_TO_USBDEV(sc));
+	data = sc->stats.phy.state;
+
+	/* XXX only need to be done before operationnal... */
+	ret = uea_read_cmv_e4(sc, 1, E4_SA_STAT, 0, 0, &sc->stats.phy.state);
+	if (ret < 0)
+		return ret;
+
+	switch (sc->stats.phy.state) {
+		case 0x0:	/* not yet synchronized */
+		case 0x1:
+		case 0x3:
+		case 0x4:
+			uea_dbg(INS_TO_USBDEV(sc), "modem not yet synchronized\n");
+			return 0;
+		case 0x5:	/* initialization */
+		case 0x6:
+		case 0x9:
+		case 0xa:
+			uea_dbg(INS_TO_USBDEV(sc), "modem initializing\n");
+			return 0;
+		case 0x2:	/* fail ... */
+			uea_info(INS_TO_USBDEV(sc), "modem synchronization failed"
+					" (may be try other cmv/dsp)\n");
+			return -EAGAIN;
+		case 0x7: 	/* operational */
+			break;
+		default:
+			uea_warn(INS_TO_USBDEV(sc), "unknown state: %x\n", sc->stats.phy.state);
+			return 0;
+	}
+
+	if (data != 7) {
+		uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_OFF, 0, NULL);
+		uea_info(INS_TO_USBDEV(sc), "modem operational\n");
+
+		/* release the dsp firmware as it is not needed until
+		 * the next failure
+		 */
+		if (sc->dsp_firm) {
+			release_firmware(sc->dsp_firm);
+			sc->dsp_firm = NULL;
+		}
+	}
+
+	/* always update it as atm layer could not be init when we switch to
+	 * operational state
+	 */
+	UPDATE_ATM_STAT(signal, ATM_PHY_SIG_FOUND);
+
+	/* wake up processes waiting for synchronization */
+	wake_up(&sc->sync_q);
+
+	/* TODO improve this state machine :
+	 * we need some CMV info : what they do and their unit
+	 * we should find the equivalent of eagle3- CMV
+	 */
+	/* check flags */
+	ret = uea_read_cmv_e4(sc, 1, E4_SA_DIAG, 0, 0, &sc->stats.phy.flags);
+	if (ret < 0)
+		return ret;
+	sc->stats.phy.mflags |= sc->stats.phy.flags;
+
+	/* in case of a flags ( for example delineation LOSS (& 0x10)),
+	 * we check the status again in order to detect the failure earlier
+	 */
+	if (sc->stats.phy.flags) {
+		uea_dbg(INS_TO_USBDEV(sc), "Stat flag = 0x%x\n",
+		       sc->stats.phy.flags);
+		if (sc->stats.phy.flags & 1) //delineation LOSS
+			return -EAGAIN;
+		if (sc->stats.phy.flags & 0x4000) //Reset Flag
+			return -EAGAIN;
+		return 0;
+	}
+
+	/* rate data may be in upper or lower half of 64 bit word, strange */
+	ret = uea_read_cmv_e4(sc, 4, E4_SA_RATE, 0, 0, tmp_arr);
+	if (ret < 0)
+		return ret;
+	data = (tmp_arr[0]) ? tmp_arr[0] : tmp_arr[1];
+	sc->stats.phy.usrate = data / 1000;
+
+	ret = uea_read_cmv_e4(sc, 4, E4_SA_RATE, 1, 0, tmp_arr);
+	if (ret < 0)
+		return ret;
+	data = (tmp_arr[0]) ? tmp_arr[0] : tmp_arr[1];
+	uea_set_bulk_timeout(sc, data / 1000);
+	sc->stats.phy.dsrate = data / 1000;
+	UPDATE_ATM_STAT(link_rate, sc->stats.phy.dsrate * 1000 / 424);
+
+	ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 68, 1, &data);
+	if (ret < 0)
+		return ret;
+	sc->stats.phy.dsattenuation = data / 10;
+
+	ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 69, 1, &data);
+	if (ret < 0)
+		return ret;
+	sc->stats.phy.usattenuation = data / 10;
+
+	ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 68, 3, &data);
+	if (ret < 0)
+		return ret;
+	sc->stats.phy.dsmargin = data / 2;
+
+	ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 69, 3, &data);
+	if (ret < 0)
+		return ret;
+	sc->stats.phy.usmargin = data / 10;
+
+	return 0;
+}
+
+static void cmvs_file_name(struct uea_softc *sc, char *const cmv_name, int ver)
+{
+	char file_arr[] = "CMVxy.bin";
+	char *file;
+
+	/* set proper name corresponding modem version and line type */
 	if (cmv_file[sc->modem_index] == NULL) {
 		if (UEA_CHIP_VERSION(sc) == ADI930)
-			file = (IS_ISDN(sc->usb_dev)) ? "CMV9i.bin" : "CMV9p.bin";
+			file_arr[3] = '9';
+		else if (UEA_CHIP_VERSION(sc) == EAGLE_IV)
+			file_arr[3] = '4';
 		else
-			file = (IS_ISDN(sc->usb_dev)) ? "CMVei.bin" : "CMVep.bin";
+			file_arr[3] = 'e';
+
+		file_arr[4] = IS_ISDN(sc) ? 'i' : 'p';
+		file = file_arr;
 	} else
 		file = cmv_file[sc->modem_index];
 
 	strcpy(cmv_name, FW_DIR);
-	strlcat(cmv_name, file, sizeof(cmv_name));
+	strlcat(cmv_name, file, FIRMWARE_NAME_MAX);
+	if (ver == 2)
+		strlcat(cmv_name, ".v2", FIRMWARE_NAME_MAX);
+}
 
+static int request_cmvs_old(struct uea_softc *sc,
+		 void **cmvs, const struct firmware **fw)
+{
+	int ret, size;
+	u8 *data;
+	char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */
+
+	cmvs_file_name(sc, cmv_name, 1);
 	ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev);
 	if (ret < 0) {
 		uea_err(INS_TO_USBDEV(sc),
@@ -1045,16 +1588,197 @@
 	}
 
 	data = (u8 *) (*fw)->data;
-	size = *data * sizeof(struct uea_cmvs) + 1;
-	if (size != (*fw)->size) {
-		uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n",
-		       cmv_name);
-		release_firmware(*fw);
-		return -EILSEQ;
+	size = (*fw)->size;
+	if (size < 1)
+		goto err_fw_corrupted;
+
+	if (size != *data * sizeof(struct uea_cmvs_v1) + 1)
+		goto err_fw_corrupted;
+
+	*cmvs = (void *)(data + 1);
+	return *data;
+
+err_fw_corrupted:
+	uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", cmv_name);
+	release_firmware(*fw);
+	return -EILSEQ;
+}
+
+static int request_cmvs(struct uea_softc *sc,
+		 void **cmvs, const struct firmware **fw, int *ver)
+{
+	int ret, size;
+	u32 crc;
+	u8 *data;
+	char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */
+
+	cmvs_file_name(sc, cmv_name, 2);
+	ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev);
+	if (ret < 0) {
+		/* if caller can handle old version, try to provide it */
+		if (*ver == 1) {
+			uea_warn(INS_TO_USBDEV(sc), "requesting firmware %s failed, "
+				"try to get older cmvs\n", cmv_name);
+			return request_cmvs_old(sc, cmvs, fw);
+		}
+		uea_err(INS_TO_USBDEV(sc),
+		       "requesting firmware %s failed with error %d\n",
+		       cmv_name, ret);
+		return ret;
 	}
 
-	*cmvs = (struct uea_cmvs *)(data + 1);
+	size = (*fw)->size;
+	data = (u8 *) (*fw)->data;
+	if (size < 4 || strncmp(data, "cmv2", 4) != 0) {
+		if (*ver == 1) {
+			uea_warn(INS_TO_USBDEV(sc), "firmware %s is corrupted, "
+				"try to get older cmvs\n", cmv_name);
+			release_firmware(*fw);
+			return request_cmvs_old(sc, cmvs, fw);
+		}
+		goto err_fw_corrupted;
+	}
+
+	*ver = 2;
+
+	data += 4;
+	size -= 4;
+	if (size < 5)
+		goto err_fw_corrupted;
+
+	crc = FW_GET_LONG(data);
+	data += 4;
+	size -= 4;
+	if (crc32_be(0, data, size) != crc)
+		goto err_fw_corrupted;
+
+	if (size != *data * sizeof(struct uea_cmvs_v2) + 1)
+		goto err_fw_corrupted;
+
+	*cmvs = (void *) (data + 1);
 	return *data;
+
+err_fw_corrupted:
+	uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", cmv_name);
+	release_firmware(*fw);
+	return -EILSEQ;
+}
+
+static int uea_send_cmvs_e1(struct uea_softc *sc)
+{
+	int i, ret, len;
+	void *cmvs_ptr;
+	const struct firmware *cmvs_fw;
+	int ver = 1; // we can handle v1 cmv firmware version;
+
+	/* Enter in R-IDLE (cmv) until instructed otherwise */
+	ret = uea_write_cmv_e1(sc, E1_SA_CNTL, 0, 1);
+	if (ret < 0)
+		return ret;
+
+	/* Dump firmware version */
+	ret = uea_read_cmv_e1(sc, E1_SA_INFO, 10, &sc->stats.phy.firmid);
+	if (ret < 0)
+		return ret;
+	uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n",
+			sc->stats.phy.firmid);
+
+	/* get options */
+ 	ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver);
+	if (ret < 0)
+		return ret;
+
+	/* send options */
+	if (ver == 1) {
+		struct uea_cmvs_v1 *cmvs_v1 = cmvs_ptr;
+
+		uea_warn(INS_TO_USBDEV(sc), "use deprecated cmvs version, "
+			"please update your firmware\n");
+
+		for (i = 0; i < len; i++) {
+			ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v1[i].address),
+						FW_GET_WORD(&cmvs_v1[i].offset),
+						FW_GET_LONG(&cmvs_v1[i].data));
+			if (ret < 0)
+				goto out;
+		}
+	} else if (ver == 2) {
+		struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr;
+
+		for (i = 0; i < len; i++) {
+			ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v2[i].address),
+						(u16) FW_GET_LONG(&cmvs_v2[i].offset),
+						FW_GET_LONG(&cmvs_v2[i].data));
+			if (ret < 0)
+				goto out;
+		}
+	} else {
+		/* This realy should not happen */
+		uea_err(INS_TO_USBDEV(sc), "bad cmvs version %d\n", ver);
+		goto out;
+	}
+
+	/* Enter in R-ACT-REQ */
+	ret = uea_write_cmv_e1(sc, E1_SA_CNTL, 0, 2);
+	uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n");
+	uea_info(INS_TO_USBDEV(sc), "modem started, waiting synchronization...\n");
+out:
+	release_firmware(cmvs_fw);
+	return ret;
+}
+
+static int uea_send_cmvs_e4(struct uea_softc *sc)
+{
+	int i, ret, len;
+	void *cmvs_ptr;
+	const struct firmware *cmvs_fw;
+	int ver = 2; // we can only handle v2 cmv firmware version;
+
+	/* Enter in R-IDLE (cmv) until instructed otherwise */
+	ret = uea_write_cmv_e4(sc, 1, E4_SA_CNTL, 0, 0, 1);
+	if (ret < 0)
+		return ret;
+
+	/* Dump firmware version */
+	/* XXX don't read the 3th byte as it is always 6 */
+	ret = uea_read_cmv_e4(sc, 2, E4_SA_INFO, 55, 0, &sc->stats.phy.firmid);
+	if (ret < 0)
+		return ret;
+	uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n",
+			sc->stats.phy.firmid);
+
+
+	/* get options */
+ 	ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver);
+	if (ret < 0)
+		return ret;
+
+	/* send options */
+	if (ver == 2) {
+		struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr;
+
+		for (i = 0; i < len; i++) {
+			ret = uea_write_cmv_e4(sc, 1,
+						FW_GET_LONG(&cmvs_v2[i].group),
+						FW_GET_LONG(&cmvs_v2[i].address),
+						FW_GET_LONG(&cmvs_v2[i].offset),
+						FW_GET_LONG(&cmvs_v2[i].data));
+			if (ret < 0)
+				goto out;
+		}
+	} else {
+		/* This realy should not happen */
+		uea_err(INS_TO_USBDEV(sc), "bad cmvs version %d\n", ver);
+		goto out;
+	}
+
+	/* Enter in R-ACT-REQ */
+	ret = uea_write_cmv_e4(sc, 1, E4_SA_CNTL, 0, 0, 2);
+	uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n");
+	uea_info(INS_TO_USBDEV(sc), "modem started, waiting synchronization...\n");
+out:
+	release_firmware(cmvs_fw);
+	return ret;
 }
 
 /* Start boot post firmware modem:
@@ -1066,9 +1790,7 @@
 static int uea_start_reset(struct uea_softc *sc)
 {
 	u16 zero = 0;	/* ;-) */
-	int i, len, ret;
-	struct uea_cmvs *cmvs;
-	const struct firmware *cmvs_fw;
+	int ret;
 
 	uea_enters(INS_TO_USBDEV(sc));
 	uea_info(INS_TO_USBDEV(sc), "(re)booting started\n");
@@ -1093,25 +1815,36 @@
 	uea_request(sc, UEA_SET_MODE, UEA_START_RESET, 0, NULL);
 
 	/* original driver use 200ms, but windows driver use 100ms */
-	msleep(100);
+	ret = uea_wait(sc, 0, msecs_to_jiffies(100));
+	if (ret < 0)
+		return ret;
 
 	/* leave reset mode */
 	uea_request(sc, UEA_SET_MODE, UEA_END_RESET, 0, NULL);
 
- 	/* clear tx and rx mailboxes */
-	uea_request(sc, UEA_SET_2183_DATA, UEA_MPTX_MAILBOX, 2, &zero);
-	uea_request(sc, UEA_SET_2183_DATA, UEA_MPRX_MAILBOX, 2, &zero);
-	uea_request(sc, UEA_SET_2183_DATA, UEA_SWAP_MAILBOX, 2, &zero);
+	if (UEA_CHIP_VERSION(sc) != EAGLE_IV) {
+ 		/* clear tx and rx mailboxes */
+		uea_request(sc, UEA_SET_2183_DATA, UEA_MPTX_MAILBOX, 2, &zero);
+		uea_request(sc, UEA_SET_2183_DATA, UEA_MPRX_MAILBOX, 2, &zero);
+		uea_request(sc, UEA_SET_2183_DATA, UEA_SWAP_MAILBOX, 2, &zero);
+	}
 
-	msleep(1000);
-	sc->cmv_function = MAKEFUNCTION(ADSLDIRECTIVE, MODEMREADY);
+	ret = uea_wait(sc, 0, msecs_to_jiffies(1000));
+	if (ret < 0)
+		return ret;
+
+	if (UEA_CHIP_VERSION(sc) == EAGLE_IV)
+		sc->cmv_dsc.e4.function = E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, E4_MODEMREADY, 1);
+	else
+		sc->cmv_dsc.e1.function = E1_MAKEFUNCTION(E1_ADSLDIRECTIVE, E1_MODEMREADY);
+
 	/* demask interrupt */
 	sc->booting = 0;
 
 	/* start loading DSP */
 	sc->pageno = 0;
 	sc->ovl = 0;
-	schedule_work(&sc->task);
+	queue_work(sc->work_q, &sc->task);
 
 	/* wait for modem ready CMV */
 	ret = wait_cmv_ack(sc);
@@ -1120,38 +1853,10 @@
 
 	uea_vdbg(INS_TO_USBDEV(sc), "Ready CMV received\n");
 
-	/* Enter in R-IDLE (cmv) until instructed otherwise */
-	ret = uea_write_cmv(sc, SA_CNTL, 0, 1);
+	ret = sc->send_cmvs(sc);
 	if (ret < 0)
 		return ret;
 
-	/* Dump firmware version */
-	ret = uea_read_cmv(sc, SA_INFO, 10, &sc->stats.phy.firmid);
-	if (ret < 0)
-		return ret;
-	uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n",
-			sc->stats.phy.firmid);
-
-	/* get options */
- 	ret = len = request_cmvs(sc, &cmvs, &cmvs_fw);
-	if (ret < 0)
-		return ret;
-
-	/* send options */
-	for (i = 0; i < len; i++) {
-		ret = uea_write_cmv(sc, FW_GET_LONG(&cmvs[i].address),
-					FW_GET_WORD(&cmvs[i].offset),
-					FW_GET_LONG(&cmvs[i].data));
-		if (ret < 0)
-			goto out;
-	}
-	/* Enter in R-ACT-REQ */
-	ret = uea_write_cmv(sc, SA_CNTL, 0, 2);
-	uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n");
-	uea_info(INS_TO_USBDEV(sc), "Modem started, "
-		"waiting synchronization\n");
-out:
-	release_firmware(cmvs_fw);
 	sc->reset = 0;
 	uea_leaves(INS_TO_USBDEV(sc));
 	return ret;
@@ -1174,12 +1879,10 @@
 		if (ret < 0 || sc->reset)
 			ret = uea_start_reset(sc);
 		if (!ret)
-			ret = uea_stat(sc);
+			ret = sc->stat(sc);
 		if (ret != -EAGAIN)
-			msleep_interruptible(1000);
- 		if (try_to_freeze())
-			uea_err(INS_TO_USBDEV(sc), "suspend/resume not supported, "
-				"please unplug/replug your modem\n");
+			uea_wait(sc, 0, msecs_to_jiffies(1000));
+		try_to_freeze();
 	}
 	uea_leaves(INS_TO_USBDEV(sc));
 	return ret;
@@ -1234,7 +1937,6 @@
 	if (ret < 0)
 		uea_err(sc->usb_dev, "elsa de-assert failed with error %d\n", ret);
 
-
 err1:
 	release_firmware(fw_entry);
 err0:
@@ -1243,40 +1945,41 @@
 }
 
 /* The modem send us an ack. First with check if it right */
-static void uea_dispatch_cmv(struct uea_softc *sc, struct cmv* cmv)
+static void uea_dispatch_cmv_e1(struct uea_softc *sc, struct intr_pkt *intr)
 {
+	struct cmv_dsc_e1 *dsc = &sc->cmv_dsc.e1;
+	struct cmv_e1 *cmv = &intr->u.e1.s2.cmv;
+
 	uea_enters(INS_TO_USBDEV(sc));
-	if (le16_to_cpu(cmv->wPreamble) != PREAMBLE)
+	if (le16_to_cpu(cmv->wPreamble) != E1_PREAMBLE)
 		goto bad1;
 
-	if (cmv->bDirection != MODEMTOHOST)
+	if (cmv->bDirection != E1_MODEMTOHOST)
 		goto bad1;
 
 	/* FIXME : ADI930 reply wrong preambule (func = 2, sub = 2) to
 	 * the first MEMACESS cmv. Ignore it...
 	 */
-	if (cmv->bFunction != sc->cmv_function) {
+	if (cmv->bFunction != dsc->function) {
 		if (UEA_CHIP_VERSION(sc) == ADI930
-				&& cmv->bFunction ==  MAKEFUNCTION(2, 2)) {
-			cmv->wIndex = cpu_to_le16(sc->cmv_idx);
-			put_unaligned(cpu_to_le32(sc->cmv_address), &cmv->dwSymbolicAddress);
-			cmv->wOffsetAddress = cpu_to_le16(sc->cmv_offset);
-		}
-		else
+				&& cmv->bFunction ==  E1_MAKEFUNCTION(2, 2)) {
+			cmv->wIndex = cpu_to_le16(dsc->idx);
+			put_unaligned(cpu_to_le32(dsc->address), &cmv->dwSymbolicAddress);
+			cmv->wOffsetAddress = cpu_to_le16(dsc->offset);
+		} else
 			goto bad2;
 	}
 
-	if (cmv->bFunction == MAKEFUNCTION(ADSLDIRECTIVE, MODEMREADY)) {
+	if (cmv->bFunction == E1_MAKEFUNCTION(E1_ADSLDIRECTIVE, E1_MODEMREADY)) {
 		wake_up_cmv_ack(sc);
 		uea_leaves(INS_TO_USBDEV(sc));
 		return;
 	}
 
 	/* in case of MEMACCESS */
-	if (le16_to_cpu(cmv->wIndex) != sc->cmv_idx ||
-	    le32_to_cpu(get_unaligned(&cmv->dwSymbolicAddress)) !=
-	    sc->cmv_address
-	    || le16_to_cpu(cmv->wOffsetAddress) != sc->cmv_offset)
+	if (le16_to_cpu(cmv->wIndex) != dsc->idx ||
+	    le32_to_cpu(get_unaligned(&cmv->dwSymbolicAddress)) != dsc->address ||
+	    le16_to_cpu(cmv->wOffsetAddress) != dsc->offset)
 		goto bad2;
 
 	sc->data = le32_to_cpu(get_unaligned(&cmv->dwData));
@@ -1289,8 +1992,8 @@
 bad2:
 	uea_err(INS_TO_USBDEV(sc), "unexpected cmv received,"
 			"Function : %d, Subfunction : %d\n",
-			FUNCTION_TYPE(cmv->bFunction),
-			FUNCTION_SUBTYPE(cmv->bFunction));
+			E1_FUNCTION_TYPE(cmv->bFunction),
+			E1_FUNCTION_SUBTYPE(cmv->bFunction));
 	uea_leaves(INS_TO_USBDEV(sc));
 	return;
 
@@ -1301,6 +2004,61 @@
 	uea_leaves(INS_TO_USBDEV(sc));
 }
 
+/* The modem send us an ack. First with check if it right */
+static void uea_dispatch_cmv_e4(struct uea_softc *sc, struct intr_pkt *intr)
+{
+	struct cmv_dsc_e4 *dsc = &sc->cmv_dsc.e4;
+	struct cmv_e4 *cmv = &intr->u.e4.s2.cmv;
+
+	uea_enters(INS_TO_USBDEV(sc));
+	uea_dbg(INS_TO_USBDEV(sc), "cmv %x %x %x %x %x %x\n",
+		be16_to_cpu(cmv->wGroup), be16_to_cpu(cmv->wFunction),
+		be16_to_cpu(cmv->wOffset), be16_to_cpu(cmv->wAddress),
+		be32_to_cpu(cmv->dwData[0]), be32_to_cpu(cmv->dwData[1]));
+
+	if (be16_to_cpu(cmv->wFunction) != dsc->function)
+		goto bad2;
+
+	if (be16_to_cpu(cmv->wFunction) == E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, E4_MODEMREADY, 1)) {
+		wake_up_cmv_ack(sc);
+		uea_leaves(INS_TO_USBDEV(sc));
+		return;
+	}
+
+	/* in case of MEMACCESS */
+	if (be16_to_cpu(cmv->wOffset) != dsc->offset ||
+	    be16_to_cpu(cmv->wGroup) != dsc->group ||
+	    be16_to_cpu(cmv->wAddress) != dsc->address)
+		goto bad2;
+
+	sc->data = be32_to_cpu(cmv->dwData[0]);
+	sc->data1 = be32_to_cpu(cmv->dwData[1]);
+	wake_up_cmv_ack(sc);
+	uea_leaves(INS_TO_USBDEV(sc));
+	return;
+
+bad2:
+	uea_err(INS_TO_USBDEV(sc), "unexpected cmv received,"
+			"Function : %d, Subfunction : %d\n",
+			E4_FUNCTION_TYPE(cmv->wFunction),
+			E4_FUNCTION_SUBTYPE(cmv->wFunction));
+	uea_leaves(INS_TO_USBDEV(sc));
+	return;
+}
+
+static void uea_schedule_load_page_e1(struct uea_softc *sc, struct intr_pkt *intr)
+{
+	sc->pageno = intr->e1_bSwapPageNo;
+	sc->ovl = intr->e1_bOvl >> 4 | intr->e1_bOvl << 4;
+	queue_work(sc->work_q, &sc->task);
+}
+
+static void uea_schedule_load_page_e4(struct uea_softc *sc, struct intr_pkt *intr)
+{
+	sc->pageno = intr->e4_bSwapPageNo;
+	queue_work(sc->work_q, &sc->task);
+}
+
 /*
  * interrupt handler
  */
@@ -1326,13 +2084,11 @@
 
 	switch (le16_to_cpu(intr->wInterrupt)) {
 	case INT_LOADSWAPPAGE:
-		sc->pageno = intr->bSwapPageNo;
-		sc->ovl = intr->bOvl >> 4 | intr->bOvl << 4;
-		schedule_work(&sc->task);
+		sc->schedule_load_page(sc, intr);
 		break;
 
 	case INT_INCOMINGCMV:
-		uea_dispatch_cmv(sc, &intr->u.s2.cmv);
+		sc->dispatch_cmv(sc, intr);
 		break;
 
 	default:
@@ -1349,35 +2105,55 @@
  */
 static int uea_boot(struct uea_softc *sc)
 {
-	int ret;
+	int ret, size;
 	struct intr_pkt *intr;
 
 	uea_enters(INS_TO_USBDEV(sc));
 
-	INIT_WORK(&sc->task, uea_load_page);
+	if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
+		size = E4_INTR_PKT_SIZE;
+		sc->dispatch_cmv = uea_dispatch_cmv_e4;
+		sc->schedule_load_page = uea_schedule_load_page_e4;
+		sc->stat = uea_stat_e4;
+		sc->send_cmvs = uea_send_cmvs_e4;
+		INIT_WORK(&sc->task, uea_load_page_e4);
+	} else {
+		size = E1_INTR_PKT_SIZE;
+		sc->dispatch_cmv = uea_dispatch_cmv_e1;
+		sc->schedule_load_page = uea_schedule_load_page_e1;
+		sc->stat = uea_stat_e1;
+		sc->send_cmvs = uea_send_cmvs_e1;
+		INIT_WORK(&sc->task, uea_load_page_e1);
+	}
+
 	init_waitqueue_head(&sc->sync_q);
-	init_waitqueue_head(&sc->cmv_ack_wait);
+
+	sc->work_q = create_workqueue("ueagle-dsp");
+	if (!sc->work_q) {
+		uea_err(INS_TO_USBDEV(sc), "cannot allocate workqueue\n");
+		uea_leaves(INS_TO_USBDEV(sc));
+		return -ENOMEM;
+	}
 
 	if (UEA_CHIP_VERSION(sc) == ADI930)
 		load_XILINX_firmware(sc);
 
-	intr = kmalloc(INTR_PKT_SIZE, GFP_KERNEL);
+	intr = kmalloc(size, GFP_KERNEL);
 	if (!intr) {
 		uea_err(INS_TO_USBDEV(sc),
 		       "cannot allocate interrupt package\n");
-		uea_leaves(INS_TO_USBDEV(sc));
-		return -ENOMEM;
+		goto err0;
 	}
 
 	sc->urb_int = usb_alloc_urb(0, GFP_KERNEL);
 	if (!sc->urb_int) {
 		uea_err(INS_TO_USBDEV(sc), "cannot allocate interrupt URB\n");
-		goto err;
+		goto err1;
 	}
 
 	usb_fill_int_urb(sc->urb_int, sc->usb_dev,
 			 usb_rcvintpipe(sc->usb_dev, UEA_INTR_PIPE),
-			 intr, INTR_PKT_SIZE, uea_intr, sc,
+			 intr, size, uea_intr, sc,
 			 sc->usb_dev->actconfig->interface[0]->altsetting[0].
 			 endpoint[0].desc.bInterval);
 
@@ -1385,7 +2161,7 @@
 	if (ret < 0) {
 		uea_err(INS_TO_USBDEV(sc),
 		       "urb submition failed with error %d\n", ret);
-		goto err;
+		goto err1;
 	}
 
 	sc->kthread = kthread_run(uea_kthread, sc, "ueagle-atm");
@@ -1399,10 +2175,12 @@
 
 err2:
 	usb_kill_urb(sc->urb_int);
-err:
+err1:
 	usb_free_urb(sc->urb_int);
 	sc->urb_int = NULL;
 	kfree(intr);
+err0:
+	destroy_workqueue(sc->work_q);
 	uea_leaves(INS_TO_USBDEV(sc));
 	return -ENOMEM;
 }
@@ -1417,15 +2195,15 @@
 	ret = kthread_stop(sc->kthread);
 	uea_dbg(INS_TO_USBDEV(sc), "kthread finish with status %d\n", ret);
 
-	/* stop any pending boot process */
-	flush_scheduled_work();
-
 	uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_ON, 0, NULL);
 
 	usb_kill_urb(sc->urb_int);
 	kfree(sc->urb_int->transfer_buffer);
 	usb_free_urb(sc->urb_int);
 
+	/* stop any pending boot process, when no one can schedule work */
+	destroy_workqueue(sc->work_q);
+
 	if (sc->dsp_firm)
 		release_firmware(sc->dsp_firm);
 	uea_leaves(INS_TO_USBDEV(sc));
@@ -1487,6 +2265,7 @@
 		char *buf)
 {
 	int ret = -ENODEV;
+	int modem_state;
 	struct uea_softc *sc;
 
 	mutex_lock(&uea_mutex);
@@ -1494,7 +2273,34 @@
 	if (!sc)
 		goto out;
 
-	switch (GET_STATUS(sc->stats.phy.state)) {
+	if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
+		switch (sc->stats.phy.state) {
+		case 0x0:	/* not yet synchronized */
+		case 0x1:
+		case 0x3:
+		case 0x4:
+			modem_state = 0;
+			break;
+		case 0x5:	/* initialization */
+		case 0x6:
+		case 0x9:
+		case 0xa:
+			modem_state = 1;
+			break;
+		case 0x7: 	/* operational */
+			modem_state = 2;
+			break;
+		case 0x2:	/* fail ... */
+			modem_state = 3;
+			break;
+		default:	/* unknown */
+			modem_state = 4;
+			break;
+		}
+	} else
+		modem_state = GET_STATUS(sc->stats.phy.state);
+
+	switch (modem_state) {
 	case 0:
 		ret = sprintf(buf, "Modem is booting\n");
 		break;
@@ -1504,9 +2310,12 @@
 	case 2:
 		ret = sprintf(buf, "Modem is operational\n");
 		break;
-	default:
+	case 3:
 		ret = sprintf(buf, "Modem synchronization failed\n");
 		break;
+	default:
+		ret = sprintf(buf, "Modem state is unknown\n");
+		break;
 	}
 out:
 	mutex_unlock(&uea_mutex);
@@ -1520,18 +2329,26 @@
 {
 	int ret = -ENODEV;
 	struct uea_softc *sc;
+	char *delin = "GOOD";
 
 	mutex_lock(&uea_mutex);
 	sc = dev_to_uea(dev);
 	if (!sc)
 		goto out;
 
-	if (sc->stats.phy.flags & 0x0C00)
-		ret = sprintf(buf, "ERROR\n");
-	else if (sc->stats.phy.flags & 0x0030)
-		ret = sprintf(buf, "LOSS\n");
-	else
-		ret = sprintf(buf, "GOOD\n");
+	if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
+		if (sc->stats.phy.flags & 0x4000)
+			delin = "RESET";
+		else if (sc->stats.phy.flags & 0x0001)
+			delin = "LOSS";
+	} else {
+		if (sc->stats.phy.flags & 0x0C00)
+			delin = "ERROR";
+		else if (sc->stats.phy.flags & 0x0030)
+			delin = "LOSS";
+	}
+
+	ret = sprintf(buf, "%s\n", delin);
 out:
 	mutex_unlock(&uea_mutex);
 	return ret;
@@ -1662,6 +2479,7 @@
 	struct usb_device *usb = interface_to_usbdev(intf);
 	struct uea_softc *sc;
 	int ret, ifnum = intf->altsetting->desc.bInterfaceNumber;
+	unsigned int alt;
 
 	uea_enters(usb);
 
@@ -1696,22 +2514,29 @@
 	sc->modem_index = (modem_index < NB_MODEM) ? modem_index++ : 0;
 	sc->driver_info = id->driver_info;
 
+	/* first try to use module parameter */
+	if (annex[sc->modem_index] == 1)
+		sc->annex = ANNEXA;
+	else if (annex[sc->modem_index] == 2)
+		sc->annex = ANNEXB;
+	/* try to autodetect annex */
+	else if (sc->driver_info & AUTO_ANNEX_A)
+		sc->annex = ANNEXA;
+	else if (sc->driver_info & AUTO_ANNEX_B)
+		sc->annex = ANNEXB;
+	else
+		sc->annex = (le16_to_cpu(sc->usb_dev->descriptor.bcdDevice) & 0x80)?ANNEXB:ANNEXA;
+
+	alt = altsetting[sc->modem_index];
 	/* ADI930 don't support iso */
-	if (UEA_CHIP_VERSION(id) != ADI930 && use_iso[sc->modem_index]) {
-		int i;
-
-		/* try set fastest alternate for inbound traffic interface */
-		for (i = FASTEST_ISO_INTF; i > 0; i--)
-			if (usb_set_interface(usb, UEA_DS_IFACE_NO, i) == 0)
-				break;
-
-		if (i > 0) {
-			uea_dbg(usb, "set alternate %d for 2 interface\n", i);
+	if (UEA_CHIP_VERSION(id) != ADI930 && alt > 0) {
+		if (alt <= 8 && usb_set_interface(usb, UEA_DS_IFACE_NO, alt) == 0) {
+			uea_dbg(usb, "set alternate %u for 2 interface\n", alt);
 			uea_info(usb, "using iso mode\n");
 			usbatm->flags |= UDSL_USE_ISOC | UDSL_IGNORE_EILSEQ;
 		} else {
-			uea_err(usb, "setting any alternate failed for "
-					"2 interface, using bulk mode\n");
+			uea_err(usb, "setting alternate %u failed for "
+					"2 interface, using bulk mode\n", alt);
 		}
 	}
 
@@ -1757,10 +2582,11 @@
 	struct usb_device *usb = interface_to_usbdev(intf);
 
 	uea_enters(usb);
-	uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) : %s %s\n",
-	       le16_to_cpu(usb->descriptor.idVendor),
-	       le16_to_cpu(usb->descriptor.idProduct),
-	       chip_name[UEA_CHIP_VERSION(id)], IS_ISDN(usb)?"isdn":"pots");
+	uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) Rev (%#X): %s\n",
+		le16_to_cpu(usb->descriptor.idVendor),
+		le16_to_cpu(usb->descriptor.idProduct),
+		le16_to_cpu(usb->descriptor.bcdDevice),
+		chip_name[UEA_CHIP_VERSION(id)]);
 
 	usb_reset_device(usb);
 
@@ -1793,24 +2619,40 @@
  * List of supported VID/PID
  */
 static const struct usb_device_id uea_ids[] = {
+	{USB_DEVICE(ANALOG_VID,	ADI930_PID_PREFIRM),	.driver_info = ADI930 | PREFIRM},
+	{USB_DEVICE(ANALOG_VID,	ADI930_PID_PSTFIRM),	.driver_info = ADI930 | PSTFIRM},
+	{USB_DEVICE(ANALOG_VID,	EAGLE_I_PID_PREFIRM),	.driver_info = EAGLE_I | PREFIRM},
+	{USB_DEVICE(ANALOG_VID,	EAGLE_I_PID_PSTFIRM),	.driver_info = EAGLE_I | PSTFIRM},
+	{USB_DEVICE(ANALOG_VID,	EAGLE_II_PID_PREFIRM),	.driver_info = EAGLE_II | PREFIRM},
+	{USB_DEVICE(ANALOG_VID,	EAGLE_II_PID_PSTFIRM),	.driver_info = EAGLE_II | PSTFIRM},
+	{USB_DEVICE(ANALOG_VID,	EAGLE_IIC_PID_PREFIRM),	.driver_info = EAGLE_II | PREFIRM},
+	{USB_DEVICE(ANALOG_VID,	EAGLE_IIC_PID_PSTFIRM),	.driver_info = EAGLE_II | PSTFIRM},
+	{USB_DEVICE(ANALOG_VID,	EAGLE_III_PID_PREFIRM),	.driver_info = EAGLE_III | PREFIRM},
+	{USB_DEVICE(ANALOG_VID,	EAGLE_III_PID_PSTFIRM),	.driver_info = EAGLE_III | PSTFIRM},
+	{USB_DEVICE(ANALOG_VID,	EAGLE_IV_PID_PREFIRM),	.driver_info = EAGLE_IV | PREFIRM},
+	{USB_DEVICE(ANALOG_VID,	EAGLE_IV_PID_PSTFIRM),	.driver_info = EAGLE_IV | PSTFIRM},
+	{USB_DEVICE(DEVOLO_VID,	DEVOLO_EAGLE_I_A_PID_PREFIRM),	.driver_info = EAGLE_I | PREFIRM},
+	{USB_DEVICE(DEVOLO_VID,	DEVOLO_EAGLE_I_A_PID_PSTFIRM),	.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A},
+	{USB_DEVICE(DEVOLO_VID,	DEVOLO_EAGLE_I_B_PID_PREFIRM),	.driver_info = EAGLE_I | PREFIRM},
+	{USB_DEVICE(DEVOLO_VID,	DEVOLO_EAGLE_I_B_PID_PSTFIRM),	.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B},
+	{USB_DEVICE(DEVOLO_VID,	DEVOLO_EAGLE_II_A_PID_PREFIRM),	.driver_info = EAGLE_II | PREFIRM},
+	{USB_DEVICE(DEVOLO_VID,	DEVOLO_EAGLE_II_A_PID_PSTFIRM),	.driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_A},
+	{USB_DEVICE(DEVOLO_VID,	DEVOLO_EAGLE_II_B_PID_PREFIRM),	.driver_info = EAGLE_II | PREFIRM},
+	{USB_DEVICE(DEVOLO_VID,	DEVOLO_EAGLE_II_B_PID_PSTFIRM),	.driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_B},
 	{USB_DEVICE(ELSA_VID,	ELSA_PID_PREFIRM),	.driver_info = ADI930 | PREFIRM},
 	{USB_DEVICE(ELSA_VID,	ELSA_PID_PSTFIRM),	.driver_info = ADI930 | PSTFIRM},
-	{USB_DEVICE(EAGLE_VID,	EAGLE_I_PID_PREFIRM),	.driver_info = EAGLE_I | PREFIRM},
-	{USB_DEVICE(EAGLE_VID,	EAGLE_I_PID_PSTFIRM),	.driver_info = EAGLE_I | PSTFIRM},
-	{USB_DEVICE(EAGLE_VID,	EAGLE_II_PID_PREFIRM),	.driver_info = EAGLE_II | PREFIRM},
-	{USB_DEVICE(EAGLE_VID,	EAGLE_II_PID_PSTFIRM),	.driver_info = EAGLE_II | PSTFIRM},
-	{USB_DEVICE(EAGLE_VID,	EAGLE_IIC_PID_PREFIRM),	.driver_info = EAGLE_II | PREFIRM},
-	{USB_DEVICE(EAGLE_VID,	EAGLE_IIC_PID_PSTFIRM),	.driver_info = EAGLE_II | PSTFIRM},
-	{USB_DEVICE(EAGLE_VID,	EAGLE_III_PID_PREFIRM),	.driver_info = EAGLE_III | PREFIRM},
-	{USB_DEVICE(EAGLE_VID,	EAGLE_III_PID_PSTFIRM),	.driver_info = EAGLE_III | PSTFIRM},
+	{USB_DEVICE(ELSA_VID,	ELSA_PID_A_PREFIRM),	.driver_info = ADI930 | PREFIRM},
+	{USB_DEVICE(ELSA_VID,	ELSA_PID_A_PSTFIRM),	.driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_A},
+	{USB_DEVICE(ELSA_VID,	ELSA_PID_B_PREFIRM),	.driver_info = ADI930 | PREFIRM},
+	{USB_DEVICE(ELSA_VID,	ELSA_PID_B_PSTFIRM),	.driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_B},
 	{USB_DEVICE(USR_VID,	MILLER_A_PID_PREFIRM),	.driver_info = EAGLE_I | PREFIRM},
-	{USB_DEVICE(USR_VID,	MILLER_A_PID_PSTFIRM),	.driver_info = EAGLE_I | PSTFIRM},
+	{USB_DEVICE(USR_VID,	MILLER_A_PID_PSTFIRM),	.driver_info = EAGLE_I | PSTFIRM  | AUTO_ANNEX_A},
 	{USB_DEVICE(USR_VID,	MILLER_B_PID_PREFIRM),	.driver_info = EAGLE_I | PREFIRM},
-	{USB_DEVICE(USR_VID,	MILLER_B_PID_PSTFIRM),	.driver_info = EAGLE_I | PSTFIRM},
+	{USB_DEVICE(USR_VID,	MILLER_B_PID_PSTFIRM),	.driver_info = EAGLE_I | PSTFIRM  | AUTO_ANNEX_B},
 	{USB_DEVICE(USR_VID,	HEINEKEN_A_PID_PREFIRM),.driver_info = EAGLE_I | PREFIRM},
-	{USB_DEVICE(USR_VID,	HEINEKEN_A_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM},
+	{USB_DEVICE(USR_VID,	HEINEKEN_A_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A},
 	{USB_DEVICE(USR_VID,	HEINEKEN_B_PID_PREFIRM),.driver_info = EAGLE_I | PREFIRM},
-	{USB_DEVICE(USR_VID,	HEINEKEN_B_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM},
+	{USB_DEVICE(USR_VID,	HEINEKEN_B_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B},
 	{}
 };
 
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index 5192cd9..ad632f2 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -28,6 +28,7 @@
  *	v0.12 - add hpoj.sourceforge.net ioctls (David Paschal)
  *	v0.13 - alloc space for statusbuf (<status> not on stack);
  *		use usb_buffer_alloc() for read buf & write buf;
+ *      none  - Maintained in Linux kernel after v0.13
  */
 
 /*
@@ -69,7 +70,6 @@
 #define USBLP_DEVICE_ID_SIZE	1024
 
 /* ioctls: */
-#define LPGETSTATUS		0x060b		/* same as in drivers/char/lp.c */
 #define IOCNR_GET_DEVICE_ID		1
 #define IOCNR_GET_PROTOCOLS		2
 #define IOCNR_SET_PROTOCOL		3
@@ -115,7 +115,7 @@
 #define USBLP_MINORS		16
 #define USBLP_MINOR_BASE	0
 
-#define USBLP_WRITE_TIMEOUT	(5000)			/* 5 seconds */
+#define USBLP_CTL_TIMEOUT	5000			/* 5 seconds */
 
 #define USBLP_FIRST_PROTOCOL	1
 #define USBLP_LAST_PROTOCOL	3
@@ -159,10 +159,12 @@
 	int			wstatus;	/* bytes written or error */
 	int			rstatus;	/* bytes ready or error */
 	unsigned int		quirks;			/* quirks flags */
+	unsigned int		flags;			/* mode flags */
 	unsigned char		used;			/* True if open */
 	unsigned char		present;		/* True if not disconnected */
 	unsigned char		bidir;			/* interface is bidirectional */
 	unsigned char		sleeping;		/* interface is suspended */
+	unsigned char		no_paper;		/* Paper Out happened */
 	unsigned char		*device_id_string;	/* IEEE 1284 DEVICE ID string (ptr) */
 							/* first 2 bytes are (big-endian) length */
 };
@@ -259,7 +261,7 @@
 
 	retval = usb_control_msg(usblp->dev,
 		dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0),
-		request, type | dir | recip, value, index, buf, len, USBLP_WRITE_TIMEOUT);
+		request, type | dir | recip, value, index, buf, len, USBLP_CTL_TIMEOUT);
 	dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d idx: %d len: %#x result: %d",
 		request, !!dir, recip, value, index, len, retval);
 	return retval < 0 ? retval : 0;
@@ -325,13 +327,11 @@
 		usblp->wstatus = status;
 	else
 		usblp->wstatus = urb->actual_length;
+	usblp->no_paper = 0;
 	usblp->wcomplete = 1;
 	wake_up(&usblp->wwait);
 	spin_unlock(&usblp->lock);
 
-	/* XXX Use usb_setup_bulk_urb when available. Talk to Marcel. */
-	kfree(urb->transfer_buffer);
-	urb->transfer_buffer = NULL;	/* Not refcounted, so to be safe... */
 	usb_free_urb(urb);
 }
 
@@ -346,16 +346,17 @@
 	unsigned char status, newerr = 0;
 	int error;
 
-	error = usblp_read_status (usblp, usblp->statusbuf);
-	if (error < 0) {
+	mutex_lock(&usblp->mut);
+	if ((error = usblp_read_status(usblp, usblp->statusbuf)) < 0) {
+		mutex_unlock(&usblp->mut);
 		if (printk_ratelimit())
 			printk(KERN_ERR
 				"usblp%d: error %d reading printer status\n",
 				usblp->minor, error);
 		return 0;
 	}
-
 	status = *usblp->statusbuf;
+	mutex_unlock(&usblp->mut);
 
 	if (~status & LP_PERRORP)
 		newerr = 3;
@@ -411,18 +412,10 @@
 		goto out;
 
 	/*
-	 * TODO: need to implement LP_ABORTOPEN + O_NONBLOCK as in drivers/char/lp.c ???
-	 * This is #if 0-ed because we *don't* want to fail an open
-	 * just because the printer is off-line.
+	 * We do not implement LP_ABORTOPEN/LPABORTOPEN for two reasons:
+	 *  - We do not want persistent state which close(2) does not clear
+	 *  - It is not used anyway, according to CUPS people
 	 */
-#if 0
-	if ((retval = usblp_check_status(usblp, 0))) {
-		retval = retval > 1 ? -EIO : -ENOSPC;
-		goto out;
-	}
-#else
-	retval = 0;
-#endif
 
 	retval = usb_autopm_get_interface(intf);
 	if (retval < 0)
@@ -463,6 +456,8 @@
 {
 	struct usblp *usblp = file->private_data;
 
+	usblp->flags &= ~LP_ABORT;
+
 	mutex_lock (&usblp_mutex);
 	usblp->used = 0;
 	if (usblp->present) {
@@ -485,8 +480,8 @@
 	poll_wait(file, &usblp->rwait, wait);
 	poll_wait(file, &usblp->wwait, wait);
 	spin_lock_irqsave(&usblp->lock, flags);
-	ret = ((!usblp->bidir || !usblp->rcomplete) ? 0 : POLLIN  | POLLRDNORM)
- 			       | (!usblp->wcomplete ? 0 : POLLOUT | POLLWRNORM);
+	ret = ((usblp->bidir && usblp->rcomplete) ? POLLIN  | POLLRDNORM : 0) |
+	   ((usblp->no_paper || usblp->wcomplete) ? POLLOUT | POLLWRNORM : 0);
 	spin_unlock_irqrestore(&usblp->lock, flags);
 	return ret;
 }
@@ -675,6 +670,13 @@
 					retval = -EFAULT;
 				break;
 
+			case LPABORT:
+				if (arg)
+					usblp->flags |= LP_ABORT;
+				else
+					usblp->flags &= ~LP_ABORT;
+				break;
+
 			default:
 				retval = -ENOTTY;
 		}
@@ -684,10 +686,30 @@
 	return retval;
 }
 
+static struct urb *usblp_new_writeurb(struct usblp *usblp, int transfer_length)
+{
+	struct urb *urb;
+	char *writebuf;
+
+	if ((writebuf = kmalloc(transfer_length, GFP_KERNEL)) == NULL)
+		return NULL;
+	if ((urb = usb_alloc_urb(0, GFP_KERNEL)) == NULL) {
+		kfree(writebuf);
+		return NULL;
+	}
+
+	usb_fill_bulk_urb(urb, usblp->dev,
+		usb_sndbulkpipe(usblp->dev,
+		 usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress),
+		writebuf, transfer_length, usblp_bulk_write, usblp);
+	urb->transfer_flags |= URB_FREE_BUFFER;
+
+	return urb;
+}
+
 static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
 {
 	struct usblp *usblp = file->private_data;
-	char *writebuf;
 	struct urb *writeurb;
 	int rv;
 	int transfer_length;
@@ -708,17 +730,11 @@
 			transfer_length = USBLP_BUF_SIZE;
 
 		rv = -ENOMEM;
-		if ((writebuf = kmalloc(USBLP_BUF_SIZE, GFP_KERNEL)) == NULL)
-			goto raise_buf;
-		if ((writeurb = usb_alloc_urb(0, GFP_KERNEL)) == NULL)
+		if ((writeurb = usblp_new_writeurb(usblp, transfer_length)) == NULL)
 			goto raise_urb;
-		usb_fill_bulk_urb(writeurb, usblp->dev,
-			usb_sndbulkpipe(usblp->dev,
-			  usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress),
-			writebuf, transfer_length, usblp_bulk_write, usblp);
 		usb_anchor_urb(writeurb, &usblp->urbs);
 
-		if (copy_from_user(writebuf,
+		if (copy_from_user(writeurb->transfer_buffer,
 				   buffer + writecount, transfer_length)) {
 			rv = -EFAULT;
 			goto raise_badaddr;
@@ -730,6 +746,7 @@
 		if ((rv = usb_submit_urb(writeurb, GFP_KERNEL)) < 0) {
 			usblp->wstatus = 0;
 			spin_lock_irq(&usblp->lock);
+			usblp->no_paper = 0;
 			usblp->wcomplete = 1;
 			wake_up(&usblp->wwait);
 			spin_unlock_irq(&usblp->lock);
@@ -747,12 +764,17 @@
 				/* Presume that it's going to complete well. */
 				writecount += transfer_length;
 			}
+			if (rv == -ENOSPC) {
+				spin_lock_irq(&usblp->lock);
+				usblp->no_paper = 1;	/* Mark for poll(2) */
+				spin_unlock_irq(&usblp->lock);
+				writecount += transfer_length;
+			}
 			/* Leave URB dangling, to be cleaned on close. */
 			goto collect_error;
 		}
 
 		if (usblp->wstatus < 0) {
-			usblp_check_status(usblp, 0);
 			rv = -EIO;
 			goto collect_error;
 		}
@@ -771,8 +793,6 @@
 	usb_unanchor_urb(writeurb);
 	usb_free_urb(writeurb);
 raise_urb:
-	kfree(writebuf);
-raise_buf:
 raise_wait:
 collect_error:		/* Out of raise sequence */
 	mutex_unlock(&usblp->wmut);
@@ -838,32 +858,36 @@
  * when O_NONBLOCK is set. So, applications setting O_NONBLOCK must use
  * select(2) or poll(2) to wait for the buffer to drain before closing.
  * Alternatively, set blocking mode with fcntl and issue a zero-size write.
- *
- * Old v0.13 code had a non-functional timeout for wait_event(). Someone forgot
- * to check the return code for timeout expiration, so it had no effect.
- * Apparently, it was intended to check for error conditons, such as out
- * of paper. It is going to return when we settle things with CUPS. XXX
  */
 static int usblp_wwait(struct usblp *usblp, int nonblock)
 {
 	DECLARE_WAITQUEUE(waita, current);
 	int rc;
+	int err = 0;
 
 	add_wait_queue(&usblp->wwait, &waita);
 	for (;;) {
+		set_current_state(TASK_INTERRUPTIBLE);
 		if (mutex_lock_interruptible(&usblp->mut)) {
 			rc = -EINTR;
 			break;
 		}
-		set_current_state(TASK_INTERRUPTIBLE);
-		if ((rc = usblp_wtest(usblp, nonblock)) < 0) {
-			mutex_unlock(&usblp->mut);
-			break;
-		}
+		rc = usblp_wtest(usblp, nonblock);
 		mutex_unlock(&usblp->mut);
-		if (rc == 0)
+		if (rc <= 0)
 			break;
-		schedule();
+
+		if (usblp->flags & LP_ABORT) {
+			if (schedule_timeout(msecs_to_jiffies(5000)) == 0) {
+				err = usblp_check_status(usblp, err);
+				if (err == 1) {	/* Paper out */
+					rc = -ENOSPC;
+					break;
+				}
+			}
+		} else {
+			schedule();
+		}
 	}
 	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&usblp->wwait, &waita);
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index cb69aa1..1a8edce 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -507,18 +507,30 @@
 }
 
 
-// hub-only!! ... and only in reset path, or usb_new_device()
-// (used by real hubs and virtual root hubs)
+/*
+ * Get the USB config descriptors, cache and parse'em
+ *
+ * hub-only!! ... and only in reset path, or usb_new_device()
+ * (used by real hubs and virtual root hubs)
+ *
+ * NOTE: if this is a WUSB device and is not authorized, we skip the
+ *       whole thing. A non-authorized USB device has no
+ *       configurations.
+ */
 int usb_get_configuration(struct usb_device *dev)
 {
 	struct device *ddev = &dev->dev;
 	int ncfg = dev->descriptor.bNumConfigurations;
-	int result = -ENOMEM;
+	int result = 0;
 	unsigned int cfgno, length;
 	unsigned char *buffer;
 	unsigned char *bigbuffer;
  	struct usb_config_descriptor *desc;
 
+	cfgno = 0;
+	if (dev->authorized == 0)	/* Not really an error */
+		goto out_not_authorized;
+	result = -ENOMEM;
 	if (ncfg > USB_MAXCONFIG) {
 		dev_warn(ddev, "too many configurations: %d, "
 		    "using maximum allowed: %d\n", ncfg, USB_MAXCONFIG);
@@ -545,14 +557,15 @@
 		goto err2;
 	desc = (struct usb_config_descriptor *)buffer;
 
-	for (cfgno = 0; cfgno < ncfg; cfgno++) {
+	result = 0;
+	for (; cfgno < ncfg; cfgno++) {
 		/* We grab just the first descriptor so we know how long
 		 * the whole configuration is */
 		result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
 		    buffer, USB_DT_CONFIG_SIZE);
 		if (result < 0) {
 			dev_err(ddev, "unable to read config index %d "
-			    "descriptor/%s\n", cfgno, "start");
+			    "descriptor/%s: %d\n", cfgno, "start", result);
 			dev_err(ddev, "chopping to %d config(s)\n", cfgno);
 			dev->descriptor.bNumConfigurations = cfgno;
 			break;
@@ -599,6 +612,7 @@
 
 err:
 	kfree(buffer);
+out_not_authorized:
 	dev->descriptor.bNumConfigurations = cfgno;
 err2:
 	if (result == -ENOMEM)
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 927a181..f013b40 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -71,6 +71,7 @@
 	void __user *userbuffer;
 	void __user *userurb;
 	struct urb *urb;
+	int status;
 	u32 secid;
 };
 
@@ -289,10 +290,8 @@
 	if (!usbfs_snoop)
 		return;
 
-	if (urb->pipe & USB_DIR_IN)
-		dev_info(&urb->dev->dev, "direction=IN\n");
-	else
-		dev_info(&urb->dev->dev, "direction=OUT\n");
+	dev_info(&urb->dev->dev, "direction=%s\n",
+			usb_urb_dir_in(urb) ? "IN" : "OUT");
 	dev_info(&urb->dev->dev, "userurb=%p\n", userurb);
 	dev_info(&urb->dev->dev, "transfer_buffer_length=%d\n",
 		 urb->transfer_buffer_length);
@@ -312,9 +311,10 @@
         spin_lock(&ps->lock);
         list_move_tail(&as->asynclist, &ps->async_completed);
         spin_unlock(&ps->lock);
+	as->status = urb->status;
 	if (as->signr) {
 		sinfo.si_signo = as->signr;
-		sinfo.si_errno = as->urb->status;
+		sinfo.si_errno = as->status;
 		sinfo.si_code = SI_ASYNCIO;
 		sinfo.si_addr = as->userurb;
 		kill_pid_info_as_uid(as->signr, &sinfo, as->pid, as->uid,
@@ -910,6 +910,7 @@
 	struct usb_ctrlrequest *dr = NULL;
 	unsigned int u, totlen, isofrmlen;
 	int ret, ifnum = -1;
+	int is_in;
 
 	if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_SHORT_NOT_OK|
 			   URB_NO_FSBR|URB_ZERO_PACKET))
@@ -924,16 +925,18 @@
 		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];
-	else
-		ep = ps->dev->ep_out [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
+	if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) {
+		is_in = 1;
+		ep = ps->dev->ep_in[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
+	} else {
+		is_in = 0;
+		ep = ps->dev->ep_out[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
+	}
 	if (!ep)
 		return -ENOENT;
 	switch(uurb->type) {
 	case USBDEVFS_URB_TYPE_CONTROL:
-		if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-				!= USB_ENDPOINT_XFER_CONTROL)
+		if (!usb_endpoint_xfer_control(&ep->desc))
 			return -EINVAL;
 		/* min 8 byte setup packet, max 8 byte setup plus an arbitrary data stage */
 		if (uurb->buffer_length < 8 || uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE))
@@ -952,23 +955,32 @@
 			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)) {
+		if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) {
+			is_in = 1;
+			uurb->endpoint |= USB_DIR_IN;
+		} else {
+			is_in = 0;
+			uurb->endpoint &= ~USB_DIR_IN;
+		}
+		if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
+				uurb->buffer, uurb->buffer_length)) {
 			kfree(dr);
 			return -EFAULT;
 		}
 		snoop(&ps->dev->dev, "control urb: bRequest=%02x "
 			"bRrequestType=%02x wValue=%04x "
 			"wIndex=%04x wLength=%04x\n",
-			dr->bRequest, dr->bRequestType, dr->wValue,
-			dr->wIndex, dr->wLength);
+			dr->bRequest, dr->bRequestType,
+			__le16_to_cpup(&dr->wValue),
+			__le16_to_cpup(&dr->wIndex),
+			__le16_to_cpup(&dr->wLength));
 		break;
 
 	case USBDEVFS_URB_TYPE_BULK:
-		switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+		switch (usb_endpoint_type(&ep->desc)) {
 		case USB_ENDPOINT_XFER_CONTROL:
 		case USB_ENDPOINT_XFER_ISOC:
 			return -EINVAL;
@@ -977,7 +989,8 @@
 		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(is_in ? VERIFY_WRITE : VERIFY_READ,
+				uurb->buffer, uurb->buffer_length))
 			return -EFAULT;
 		snoop(&ps->dev->dev, "bulk urb\n");
 		break;
@@ -986,8 +999,7 @@
 		/* arbitrary limit */
 		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)
+		if (!usb_endpoint_xfer_isoc(&ep->desc))
 			return -EINVAL;
 		isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb->number_of_packets;
 		if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL)))
@@ -1014,12 +1026,12 @@
 
 	case USBDEVFS_URB_TYPE_INTERRUPT:
 		uurb->number_of_packets = 0;
-		if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-				!= USB_ENDPOINT_XFER_INT)
+		if (!usb_endpoint_xfer_int(&ep->desc))
 			return -EINVAL;
 		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(is_in ? VERIFY_WRITE : VERIFY_READ,
+				uurb->buffer, uurb->buffer_length))
 			return -EFAULT;
 		snoop(&ps->dev->dev, "interrupt urb\n");
 		break;
@@ -1039,8 +1051,11 @@
 		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->pipe = (uurb->type << 30) |
+			__create_pipe(ps->dev, uurb->endpoint & 0xf) |
+			(uurb->endpoint & USB_DIR_IN);
+        as->urb->transfer_flags = uurb->flags |
+			(is_in ? URB_DIR_IN : URB_DIR_OUT);
 	as->urb->transfer_buffer_length = uurb->buffer_length;
 	as->urb->setup_packet = (unsigned char*)dr;
 	as->urb->start_frame = uurb->start_frame;
@@ -1070,13 +1085,13 @@
 	as->uid = current->uid;
 	as->euid = current->euid;
 	security_task_getsecid(current, &as->secid);
-	if (!(uurb->endpoint & USB_DIR_IN)) {
-		if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, as->urb->transfer_buffer_length)) {
+	if (!is_in) {
+		if (copy_from_user(as->urb->transfer_buffer, uurb->buffer,
+				as->urb->transfer_buffer_length)) {
 			free_async(as);
 			return -EFAULT;
 		}
 	}
-	snoop(&as->urb->dev->dev, "submit urb\n");
 	snoop_urb(as->urb, as->userurb);
         async_newpending(as);
         if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) {
@@ -1119,14 +1134,14 @@
 	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))
+	if (put_user(as->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)) {
+	if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
 		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))
@@ -1233,14 +1248,14 @@
 	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))
+	if (put_user(as->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)) {
+	if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
 		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))
@@ -1576,6 +1591,7 @@
 }
 
 const struct file_operations usbdev_file_operations = {
+	.owner = 	THIS_MODULE,
 	.llseek =	usbdev_lseek,
 	.read =		usbdev_read,
 	.poll =		usbdev_poll,
@@ -1625,10 +1641,7 @@
 };
 #endif
 
-static struct cdev usb_device_cdev = {
-	.kobj   = {.name = "usb_device", },
-	.owner  = THIS_MODULE,
-};
+static struct cdev usb_device_cdev;
 
 int __init usb_devio_init(void)
 {
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 63b1243..8586817 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -202,6 +202,11 @@
 	intf = to_usb_interface(dev);
 	udev = interface_to_usbdev(intf);
 
+ 	if (udev->authorized == 0) {
+ 		dev_err(&intf->dev, "Device is not authorized for usage\n");
+ 		return -ENODEV;
+ 	}
+
 	id = usb_match_id(intf, driver->id_table);
 	if (!id)
 		id = usb_match_dynamic_id(intf, driver);
@@ -576,12 +581,9 @@
 }
 
 #ifdef	CONFIG_HOTPLUG
-static int usb_uevent(struct device *dev, char **envp, int num_envp,
-		      char *buffer, int buffer_size)
+static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct usb_device *usb_dev;
-	int i = 0;
-	int length = 0;
 
 	if (!dev)
 		return -ENODEV;
@@ -610,51 +612,39 @@
 	 * all the device descriptors we don't tell them about.  Or
 	 * act as usermode drivers.
 	 */
-	if (add_uevent_var(envp, num_envp, &i,
-			   buffer, buffer_size, &length,
-			   "DEVICE=/proc/bus/usb/%03d/%03d",
+	if (add_uevent_var(env, "DEVICE=/proc/bus/usb/%03d/%03d",
 			   usb_dev->bus->busnum, usb_dev->devnum))
 		return -ENOMEM;
 #endif
 
 	/* per-device configurations are common */
-	if (add_uevent_var(envp, num_envp, &i,
-			   buffer, buffer_size, &length,
-			   "PRODUCT=%x/%x/%x",
+	if (add_uevent_var(env, "PRODUCT=%x/%x/%x",
 			   le16_to_cpu(usb_dev->descriptor.idVendor),
 			   le16_to_cpu(usb_dev->descriptor.idProduct),
 			   le16_to_cpu(usb_dev->descriptor.bcdDevice)))
 		return -ENOMEM;
 
 	/* class-based driver binding models */
-	if (add_uevent_var(envp, num_envp, &i,
-			   buffer, buffer_size, &length,
-			   "TYPE=%d/%d/%d",
+	if (add_uevent_var(env, "TYPE=%d/%d/%d",
 			   usb_dev->descriptor.bDeviceClass,
 			   usb_dev->descriptor.bDeviceSubClass,
 			   usb_dev->descriptor.bDeviceProtocol))
 		return -ENOMEM;
 
-	if (add_uevent_var(envp, num_envp, &i,
-			   buffer, buffer_size, &length,
-			   "BUSNUM=%03d",
+	if (add_uevent_var(env, "BUSNUM=%03d",
 			   usb_dev->bus->busnum))
 		return -ENOMEM;
 
-	if (add_uevent_var(envp, num_envp, &i,
-			   buffer, buffer_size, &length,
-			   "DEVNUM=%03d",
+	if (add_uevent_var(env, "DEVNUM=%03d",
 			   usb_dev->devnum))
 		return -ENOMEM;
 
-	envp[i] = NULL;
 	return 0;
 }
 
 #else
 
-static int usb_uevent(struct device *dev, char **envp,
-		      int num_envp, char *buffer, int buffer_size)
+static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	return -ENODEV;
 }
@@ -945,11 +935,11 @@
 #ifdef	CONFIG_USB_SUSPEND
 
 /* Internal routine to check whether we may autosuspend a device. */
-static int autosuspend_check(struct usb_device *udev)
+static int autosuspend_check(struct usb_device *udev, int reschedule)
 {
 	int			i;
 	struct usb_interface	*intf;
-	unsigned long		suspend_time;
+	unsigned long		suspend_time, j;
 
 	/* For autosuspend, fail fast if anything is in use or autosuspend
 	 * is disabled.  Also fail if any interfaces require remote wakeup
@@ -991,20 +981,20 @@
 	}
 
 	/* If everything is okay but the device hasn't been idle for long
-	 * enough, queue a delayed autosuspend request.
+	 * enough, queue a delayed autosuspend request.  If the device
+	 * _has_ been idle for long enough and the reschedule flag is set,
+	 * likewise queue a delayed (1 second) autosuspend request.
 	 */
-	if (time_after(suspend_time, jiffies)) {
+	j = jiffies;
+	if (time_before(j, suspend_time))
+		reschedule = 1;
+	else
+		suspend_time = j + HZ;
+	if (reschedule) {
 		if (!timer_pending(&udev->autosuspend.timer)) {
-
-			/* The value of jiffies may change between the
-			 * time_after() comparison above and the subtraction
-			 * below.  That's okay; the system behaves sanely
-			 * when a timer is registered for the present moment
-			 * or for the past.
-			 */
 			queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
-				round_jiffies_relative(suspend_time - jiffies));
-			}
+				round_jiffies_relative(suspend_time - j));
+		}
 		return -EAGAIN;
 	}
 	return 0;
@@ -1012,7 +1002,7 @@
 
 #else
 
-static inline int autosuspend_check(struct usb_device *udev)
+static inline int autosuspend_check(struct usb_device *udev, int reschedule)
 {
 	return 0;
 }
@@ -1069,7 +1059,7 @@
 	udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
 
 	if (udev->auto_pm) {
-		status = autosuspend_check(udev);
+		status = autosuspend_check(udev, 0);
 		if (status < 0)
 			goto done;
 	}
@@ -1083,15 +1073,8 @@
 				break;
 		}
 	}
-	if (status == 0) {
-
-		/* Non-root devices don't need to do anything for FREEZE
-		 * or PRETHAW. */
-		if (udev->parent && (msg.event == PM_EVENT_FREEZE ||
-				msg.event == PM_EVENT_PRETHAW))
-			goto done;
+	if (status == 0)
 		status = usb_suspend_device(udev, msg);
-	}
 
 	/* If the suspend failed, resume interfaces that did get suspended */
 	if (status != 0) {
@@ -1102,12 +1085,24 @@
 
 		/* Try another autosuspend when the interfaces aren't busy */
 		if (udev->auto_pm)
-			autosuspend_check(udev);
+			autosuspend_check(udev, status == -EBUSY);
 
-	/* If the suspend succeeded, propagate it up the tree */
+	/* If the suspend succeeded then prevent any more URB submissions,
+	 * flush any outstanding URBs, and propagate the suspend up the tree.
+	 */
 	} else {
 		cancel_delayed_work(&udev->autosuspend);
-		if (parent)
+		udev->can_submit = 0;
+		for (i = 0; i < 16; ++i) {
+			usb_hcd_flush_endpoint(udev, udev->ep_out[i]);
+			usb_hcd_flush_endpoint(udev, udev->ep_in[i]);
+		}
+
+		/* If this is just a FREEZE or a PRETHAW, udev might
+		 * not really be suspended.  Only true suspends get
+		 * propagated up the device tree.
+		 */
+		if (parent && udev->state == USB_STATE_SUSPENDED)
 			usb_autosuspend_device(parent);
 	}
 
@@ -1156,6 +1151,7 @@
 		status = -ENODEV;
 		goto done;
 	}
+	udev->can_submit = 1;
 
 	/* Propagate the resume up the tree, if necessary */
 	if (udev->state == USB_STATE_SUSPENDED) {
@@ -1529,9 +1525,21 @@
 
 static int usb_suspend(struct device *dev, pm_message_t message)
 {
+	struct usb_device	*udev;
+
 	if (!is_usb_device(dev))	/* Ignore PM for interfaces */
 		return 0;
-	return usb_external_suspend_device(to_usb_device(dev), message);
+	udev = to_usb_device(dev);
+
+	/* If udev is already suspended, we can skip this suspend and
+	 * we should also skip the upcoming system resume. */
+	if (udev->state == USB_STATE_SUSPENDED) {
+		udev->skip_sys_resume = 1;
+		return 0;
+	}
+
+	udev->skip_sys_resume = 0;
+	return usb_external_suspend_device(udev, message);
 }
 
 static int usb_resume(struct device *dev)
@@ -1542,13 +1550,14 @@
 		return 0;
 	udev = to_usb_device(dev);
 
-	/* If autoresume is disabled then we also want to prevent resume
-	 * during system wakeup.  However, a "persistent-device" reset-resume
-	 * after power loss counts as a wakeup event.  So allow a
-	 * reset-resume to occur if remote wakeup is enabled. */
-	if (udev->autoresume_disabled) {
+	/* If udev->skip_sys_resume is set then udev was already suspended
+	 * when the system suspend started, so we don't want to resume
+	 * udev during this system wakeup.  However a reset-resume counts
+	 * as a wakeup event, so allow a reset-resume to occur if remote
+	 * wakeup is enabled. */
+	if (udev->skip_sys_resume) {
 		if (!(udev->reset_resume && udev->do_remote_wakeup))
-			return -EPERM;
+			return -EHOSTUNREACH;
 	}
 	return usb_external_resume_device(udev);
 }
diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c
index e0ec704..7dc123d 100644
--- a/drivers/usb/core/endpoint.c
+++ b/drivers/usb/core/endpoint.c
@@ -267,7 +267,6 @@
 {
 	struct ep_device *ep_dev = to_ep_device(dev);
 
-	dev_dbg(dev, "%s called for %s\n", __FUNCTION__, dev->bus_id);
 	endpoint_free_minor(ep_dev);
 	kfree(ep_dev);
 }
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index b2fc2b1..c1cb94e 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -40,7 +40,7 @@
 		&& desc->bInterfaceProtocol == 1;
 }
 
-static int choose_configuration(struct usb_device *udev)
+int usb_choose_configuration(struct usb_device *udev)
 {
 	int i;
 	int num_configs;
@@ -161,17 +161,20 @@
 	/* Choose and set the configuration.  This registers the interfaces
 	 * with the driver core and lets interface drivers bind to them.
 	 */
-	c = choose_configuration(udev);
-	if (c >= 0) {
-		err = usb_set_configuration(udev, c);
-		if (err) {
-			dev_err(&udev->dev, "can't set config #%d, error %d\n",
+	if (udev->authorized == 0)
+		dev_err(&udev->dev, "Device is not authorized for usage\n");
+	else {
+		c = usb_choose_configuration(udev);
+		if (c >= 0) {
+			err = usb_set_configuration(udev, c);
+			if (err) {
+				dev_err(&udev->dev, "can't set config #%d, error %d\n",
 					c, err);
-			/* This need not be fatal.  The user can try to
-			 * set other configurations. */
+				/* This need not be fatal.  The user can try to
+				 * set other configurations. */
+			}
 		}
 	}
-
 	/* USB device state == configured ... usable */
 	usb_notify_add_device(udev);
 
@@ -203,8 +206,13 @@
 	 */
 	if (!udev->parent)
 		rc = hcd_bus_suspend(udev);
+
+	/* Non-root devices don't need to do anything for FREEZE or PRETHAW */
+	else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW)
+		rc = 0;
 	else
 		rc = usb_port_suspend(udev);
+
 	return rc;
 }
 
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 42ef1d5..3dd997d 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -356,10 +356,18 @@
 	const u8	*bufp = tbuf;
 	int		len = 0;
 	int		patch_wakeup = 0;
-	unsigned long	flags;
-	int		status = 0;
+	int		status;
 	int		n;
 
+	might_sleep();
+
+	spin_lock_irq(&hcd_root_hub_lock);
+	status = usb_hcd_link_urb_to_ep(hcd, urb);
+	spin_unlock_irq(&hcd_root_hub_lock);
+	if (status)
+		return status;
+	urb->hcpriv = hcd;	/* Indicate it's queued */
+
 	cmd = (struct usb_ctrlrequest *) urb->setup_packet;
 	typeReq  = (cmd->bRequestType << 8) | cmd->bRequest;
 	wValue   = le16_to_cpu (cmd->wValue);
@@ -523,13 +531,18 @@
 	}
 
 	/* 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);
-	local_irq_restore (flags);
+	spin_lock_irq(&hcd_root_hub_lock);
+	usb_hcd_unlink_urb_from_ep(hcd, urb);
+
+	/* This peculiar use of spinlocks echoes what real HC drivers do.
+	 * Avoiding calls to local_irq_disable/enable makes the code
+	 * RT-friendly.
+	 */
+	spin_unlock(&hcd_root_hub_lock);
+	usb_hcd_giveback_urb(hcd, urb, status);
+	spin_lock(&hcd_root_hub_lock);
+
+	spin_unlock_irq(&hcd_root_hub_lock);
 	return 0;
 }
 
@@ -559,31 +572,23 @@
 	if (length > 0) {
 
 		/* try to complete the status urb */
-		local_irq_save (flags);
-		spin_lock(&hcd_root_hub_lock);
+		spin_lock_irqsave(&hcd_root_hub_lock, flags);
 		urb = hcd->status_urb;
 		if (urb) {
-			spin_lock(&urb->lock);
-			if (urb->status == -EINPROGRESS) {
-				hcd->poll_pending = 0;
-				hcd->status_urb = NULL;
-				urb->status = 0;
-				urb->hcpriv = NULL;
-				urb->actual_length = length;
-				memcpy(urb->transfer_buffer, buffer, length);
-			} else		/* urb has been unlinked */
-				length = 0;
-			spin_unlock(&urb->lock);
-		} else
-			length = 0;
-		spin_unlock(&hcd_root_hub_lock);
+			hcd->poll_pending = 0;
+			hcd->status_urb = NULL;
+			urb->actual_length = length;
+			memcpy(urb->transfer_buffer, buffer, length);
 
-		/* local irqs are always blocked in completions */
-		if (length > 0)
-			usb_hcd_giveback_urb (hcd, urb);
-		else
+			usb_hcd_unlink_urb_from_ep(hcd, urb);
+			spin_unlock(&hcd_root_hub_lock);
+			usb_hcd_giveback_urb(hcd, urb, 0);
+			spin_lock(&hcd_root_hub_lock);
+		} else {
+			length = 0;
 			hcd->poll_pending = 1;
-		local_irq_restore (flags);
+		}
+		spin_unlock_irqrestore(&hcd_root_hub_lock, flags);
 	}
 
 	/* The USB 2.0 spec says 256 ms.  This is close enough and won't
@@ -611,33 +616,35 @@
 	int		len = 1 + (urb->dev->maxchild / 8);
 
 	spin_lock_irqsave (&hcd_root_hub_lock, flags);
-	if (urb->status != -EINPROGRESS)	/* already unlinked */
-		retval = urb->status;
-	else if (hcd->status_urb || urb->transfer_buffer_length < len) {
+	if (hcd->status_urb || urb->transfer_buffer_length < len) {
 		dev_dbg (hcd->self.controller, "not queuing rh status urb\n");
 		retval = -EINVAL;
-	} else {
-		hcd->status_urb = urb;
-		urb->hcpriv = hcd;	/* indicate it's queued */
-
-		if (!hcd->uses_new_polling)
-			mod_timer (&hcd->rh_timer,
-				(jiffies/(HZ/4) + 1) * (HZ/4));
-
-		/* If a status change has already occurred, report it ASAP */
-		else if (hcd->poll_pending)
-			mod_timer (&hcd->rh_timer, jiffies);
-		retval = 0;
+		goto done;
 	}
+
+	retval = usb_hcd_link_urb_to_ep(hcd, urb);
+	if (retval)
+		goto done;
+
+	hcd->status_urb = urb;
+	urb->hcpriv = hcd;	/* indicate it's queued */
+	if (!hcd->uses_new_polling)
+		mod_timer(&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4));
+
+	/* If a status change has already occurred, report it ASAP */
+	else if (hcd->poll_pending)
+		mod_timer(&hcd->rh_timer, jiffies);
+	retval = 0;
+ done:
 	spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
 	return retval;
 }
 
 static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
 {
-	if (usb_pipeint (urb->pipe))
+	if (usb_endpoint_xfer_int(&urb->ep->desc))
 		return rh_queue_status (hcd, urb);
-	if (usb_pipecontrol (urb->pipe))
+	if (usb_endpoint_xfer_control(&urb->ep->desc))
 		return rh_call_control (hcd, urb);
 	return -EINVAL;
 }
@@ -647,32 +654,96 @@
 /* Unlinks of root-hub control URBs are legal, but they don't do anything
  * since these URBs always execute synchronously.
  */
-static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int usb_rh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
 	unsigned long	flags;
+	int		rc;
 
-	if (usb_pipeendpoint(urb->pipe) == 0) {	/* Control URB */
+	spin_lock_irqsave(&hcd_root_hub_lock, flags);
+	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (rc)
+		goto done;
+
+	if (usb_endpoint_num(&urb->ep->desc) == 0) {	/* Control URB */
 		;	/* Do nothing */
 
 	} else {				/* Status URB */
 		if (!hcd->uses_new_polling)
 			del_timer (&hcd->rh_timer);
-		local_irq_save (flags);
-		spin_lock (&hcd_root_hub_lock);
 		if (urb == hcd->status_urb) {
 			hcd->status_urb = NULL;
-			urb->hcpriv = NULL;
-		} else
-			urb = NULL;		/* wasn't fully queued */
-		spin_unlock (&hcd_root_hub_lock);
-		if (urb)
-			usb_hcd_giveback_urb (hcd, urb);
-		local_irq_restore (flags);
-	}
+			usb_hcd_unlink_urb_from_ep(hcd, urb);
 
-	return 0;
+			spin_unlock(&hcd_root_hub_lock);
+			usb_hcd_giveback_urb(hcd, urb, status);
+			spin_lock(&hcd_root_hub_lock);
+		}
+	}
+ done:
+	spin_unlock_irqrestore(&hcd_root_hub_lock, flags);
+	return rc;
 }
 
+
+
+/*
+ * Show & store the current value of authorized_default
+ */
+static ssize_t usb_host_authorized_default_show(struct device *dev,
+						struct device_attribute *attr,
+						char *buf)
+{
+	struct usb_device *rh_usb_dev = to_usb_device(dev);
+	struct usb_bus *usb_bus = rh_usb_dev->bus;
+	struct usb_hcd *usb_hcd;
+
+	if (usb_bus == NULL)	/* FIXME: not sure if this case is possible */
+		return -ENODEV;
+	usb_hcd = bus_to_hcd(usb_bus);
+	return snprintf(buf, PAGE_SIZE, "%u\n", usb_hcd->authorized_default);
+}
+
+static ssize_t usb_host_authorized_default_store(struct device *dev,
+						 struct device_attribute *attr,
+						 const char *buf, size_t size)
+{
+	ssize_t result;
+	unsigned val;
+	struct usb_device *rh_usb_dev = to_usb_device(dev);
+	struct usb_bus *usb_bus = rh_usb_dev->bus;
+	struct usb_hcd *usb_hcd;
+
+	if (usb_bus == NULL)	/* FIXME: not sure if this case is possible */
+		return -ENODEV;
+	usb_hcd = bus_to_hcd(usb_bus);
+	result = sscanf(buf, "%u\n", &val);
+	if (result == 1) {
+		usb_hcd->authorized_default = val? 1 : 0;
+		result = size;
+	}
+	else
+		result = -EINVAL;
+	return result;
+}
+
+static DEVICE_ATTR(authorized_default, 0644,
+	    usb_host_authorized_default_show,
+	    usb_host_authorized_default_store);
+
+
+/* Group all the USB bus attributes */
+static struct attribute *usb_bus_attrs[] = {
+		&dev_attr_authorized_default.attr,
+		NULL,
+};
+
+static struct attribute_group usb_bus_attr_group = {
+	.name = NULL,	/* we want them in the same directory */
+	.attrs = usb_bus_attrs,
+};
+
+
+
 /*-------------------------------------------------------------------------*/
 
 static struct class *usb_host_class;
@@ -726,27 +797,23 @@
  */
 static int usb_register_bus(struct usb_bus *bus)
 {
+	int result = -E2BIG;
 	int busnum;
 
 	mutex_lock(&usb_bus_list_lock);
 	busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1);
-	if (busnum < USB_MAXBUS) {
-		set_bit (busnum, busmap.busmap);
-		bus->busnum = busnum;
-	} else {
+	if (busnum >= USB_MAXBUS) {
 		printk (KERN_ERR "%s: too many buses\n", usbcore_name);
-		mutex_unlock(&usb_bus_list_lock);
-		return -E2BIG;
+		goto error_find_busnum;
 	}
-
+	set_bit (busnum, busmap.busmap);
+	bus->busnum = busnum;
 	bus->class_dev = class_device_create(usb_host_class, NULL, MKDEV(0,0),
-					     bus->controller, "usb_host%d", busnum);
-	if (IS_ERR(bus->class_dev)) {
-		clear_bit(busnum, busmap.busmap);
-		mutex_unlock(&usb_bus_list_lock);
-		return PTR_ERR(bus->class_dev);
-	}
-
+					     bus->controller, "usb_host%d",
+					     busnum);
+	result = PTR_ERR(bus->class_dev);
+	if (IS_ERR(bus->class_dev))
+		goto error_create_class_dev;
 	class_set_devdata(bus->class_dev, bus);
 
 	/* Add it to the local list of buses */
@@ -755,8 +822,15 @@
 
 	usb_notify_add_bus(bus);
 
-	dev_info (bus->controller, "new USB bus registered, assigned bus number %d\n", bus->busnum);
+	dev_info (bus->controller, "new USB bus registered, assigned bus "
+		  "number %d\n", bus->busnum);
 	return 0;
+
+error_create_class_dev:
+	clear_bit(busnum, busmap.busmap);
+error_find_busnum:
+	mutex_unlock(&usb_bus_list_lock);
+	return result;
 }
 
 /**
@@ -908,103 +982,145 @@
 
 /*-------------------------------------------------------------------------*/
 
-static void urb_unlink(struct usb_hcd *hcd, struct urb *urb)
-{
-	unsigned long		flags;
-
-	/* clear all state linking urb to this dev (and hcd) */
-	spin_lock_irqsave(&hcd_urb_list_lock, flags);
-	list_del_init (&urb->urb_list);
-	spin_unlock_irqrestore(&hcd_urb_list_lock, flags);
-
-	if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
-		if (usb_pipecontrol (urb->pipe)
-			&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
-			dma_unmap_single (hcd->self.controller, urb->setup_dma,
-					sizeof (struct usb_ctrlrequest),
-					DMA_TO_DEVICE);
-		if (urb->transfer_buffer_length != 0
-			&& !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
-			dma_unmap_single (hcd->self.controller,
-					urb->transfer_dma,
-					urb->transfer_buffer_length,
-					usb_pipein (urb->pipe)
-					    ? DMA_FROM_DEVICE
-					    : DMA_TO_DEVICE);
-	}
-}
-
-/* may be called in any context with a valid urb->dev usecount
- * caller surrenders "ownership" of urb
- * expects usb_submit_urb() to have sanity checked and conditioned all
- * inputs in the urb
+/**
+ * usb_hcd_link_urb_to_ep - add an URB to its endpoint queue
+ * @hcd: host controller to which @urb was submitted
+ * @urb: URB being submitted
+ *
+ * Host controller drivers should call this routine in their enqueue()
+ * method.  The HCD's private spinlock must be held and interrupts must
+ * be disabled.  The actions carried out here are required for URB
+ * submission, as well as for endpoint shutdown and for usb_kill_urb.
+ *
+ * Returns 0 for no error, otherwise a negative error code (in which case
+ * the enqueue() method must fail).  If no error occurs but enqueue() fails
+ * anyway, it must call usb_hcd_unlink_urb_from_ep() before releasing
+ * the private spinlock and returning.
  */
-int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
+int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb)
 {
-	int			status;
-	struct usb_hcd		*hcd = bus_to_hcd(urb->dev->bus);
-	struct usb_host_endpoint *ep;
-	unsigned long		flags;
+	int		rc = 0;
 
-	if (!hcd)
-		return -ENODEV;
+	spin_lock(&hcd_urb_list_lock);
 
-	usbmon_urb_submit(&hcd->self, urb);
-
-	/*
-	 * Atomically queue the urb,  first to our records, then to the HCD.
-	 * Access to urb->status is controlled by urb->lock ... changes on
-	 * i/o completion (normal or fault) or unlinking.
-	 */
-
-	// FIXME:  verify that quiescing hc works right (RH cleans up)
-
-	spin_lock_irqsave(&hcd_urb_list_lock, flags);
-	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 HC_STATE_RUNNING:
-	case HC_STATE_RESUMING:
-		list_add_tail (&urb->urb_list, &ep->urb_list);
-		status = 0;
-		break;
-	default:
-		status = -ESHUTDOWN;
-		break;
-	}
-	spin_unlock_irqrestore(&hcd_urb_list_lock, flags);
-	if (status) {
-		INIT_LIST_HEAD (&urb->urb_list);
-		usbmon_urb_submit_error(&hcd->self, urb, status);
-		return status;
-	}
-
-	/* increment urb's reference count as part of giving it to the HCD
-	 * (which now controls it).  HCD guarantees that it either returns
-	 * an error or calls giveback(), but not both.
-	 */
-	urb = usb_get_urb (urb);
-	atomic_inc (&urb->use_count);
-
-	if (is_root_hub(urb->dev)) {
-		/* NOTE:  requirement on hub callers (usbfs and the hub
-		 * driver, for now) that URBs' urb->transfer_buffer be
-		 * valid and usb_buffer_{sync,unmap}() not be needed, since
-		 * they could clobber root hub response data.
-		 */
-		status = rh_urb_enqueue (hcd, urb);
+	/* Check that the URB isn't being killed */
+	if (unlikely(urb->reject)) {
+		rc = -EPERM;
 		goto done;
 	}
 
-	/* lower level hcd code should use *_dma exclusively,
+	if (unlikely(!urb->ep->enabled)) {
+		rc = -ENOENT;
+		goto done;
+	}
+
+	if (unlikely(!urb->dev->can_submit)) {
+		rc = -EHOSTUNREACH;
+		goto done;
+	}
+
+	/*
+	 * Check the host controller's state and add the URB to the
+	 * endpoint's queue.
+	 */
+	switch (hcd->state) {
+	case HC_STATE_RUNNING:
+	case HC_STATE_RESUMING:
+		urb->unlinked = 0;
+		list_add_tail(&urb->urb_list, &urb->ep->urb_list);
+		break;
+	default:
+		rc = -ESHUTDOWN;
+		goto done;
+	}
+ done:
+	spin_unlock(&hcd_urb_list_lock);
+	return rc;
+}
+EXPORT_SYMBOL_GPL(usb_hcd_link_urb_to_ep);
+
+/**
+ * usb_hcd_check_unlink_urb - check whether an URB may be unlinked
+ * @hcd: host controller to which @urb was submitted
+ * @urb: URB being checked for unlinkability
+ * @status: error code to store in @urb if the unlink succeeds
+ *
+ * Host controller drivers should call this routine in their dequeue()
+ * method.  The HCD's private spinlock must be held and interrupts must
+ * be disabled.  The actions carried out here are required for making
+ * sure than an unlink is valid.
+ *
+ * Returns 0 for no error, otherwise a negative error code (in which case
+ * the dequeue() method must fail).  The possible error codes are:
+ *
+ *	-EIDRM: @urb was not submitted or has already completed.
+ *		The completion function may not have been called yet.
+ *
+ *	-EBUSY: @urb has already been unlinked.
+ */
+int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
+		int status)
+{
+	struct list_head	*tmp;
+
+	/* insist the urb is still queued */
+	list_for_each(tmp, &urb->ep->urb_list) {
+		if (tmp == &urb->urb_list)
+			break;
+	}
+	if (tmp != &urb->urb_list)
+		return -EIDRM;
+
+	/* Any status except -EINPROGRESS means something already started to
+	 * unlink this URB from the hardware.  So there's no more work to do.
+	 */
+	if (urb->unlinked)
+		return -EBUSY;
+	urb->unlinked = status;
+
+	/* IRQ setup can easily be broken so that USB controllers
+	 * never get completion IRQs ... maybe even the ones we need to
+	 * finish unlinking the initial failed usb_set_address()
+	 * or device descriptor fetch.
+	 */
+	if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) &&
+			!is_root_hub(urb->dev)) {
+		dev_warn(hcd->self.controller, "Unlink after no-IRQ?  "
+			"Controller is probably using the wrong IRQ.\n");
+		set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_hcd_check_unlink_urb);
+
+/**
+ * usb_hcd_unlink_urb_from_ep - remove an URB from its endpoint queue
+ * @hcd: host controller to which @urb was submitted
+ * @urb: URB being unlinked
+ *
+ * Host controller drivers should call this routine before calling
+ * usb_hcd_giveback_urb().  The HCD's private spinlock must be held and
+ * interrupts must be disabled.  The actions carried out here are required
+ * for URB completion.
+ */
+void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb)
+{
+	/* clear all state linking urb to this dev (and hcd) */
+	spin_lock(&hcd_urb_list_lock);
+	list_del_init(&urb->urb_list);
+	spin_unlock(&hcd_urb_list_lock);
+}
+EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep);
+
+static void map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
+{
+	/* Map the URB's buffers for DMA access.
+	 * Lower level HCD code should use *_dma exclusively,
 	 * unless it uses pio or talks to another transport.
 	 */
-	if (hcd->self.uses_dma) {
-		if (usb_pipecontrol (urb->pipe)
+	if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
+		if (usb_endpoint_xfer_control(&urb->ep->desc)
 			&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
 			urb->setup_dma = dma_map_single (
 					hcd->self.controller,
@@ -1017,20 +1133,75 @@
 					hcd->self.controller,
 					urb->transfer_buffer,
 					urb->transfer_buffer_length,
-					usb_pipein (urb->pipe)
+					usb_urb_dir_in(urb)
 					    ? DMA_FROM_DEVICE
 					    : DMA_TO_DEVICE);
 	}
+}
 
-	status = hcd->driver->urb_enqueue (hcd, ep, urb, mem_flags);
-done:
-	if (unlikely (status)) {
-		urb_unlink(hcd, urb);
-		atomic_dec (&urb->use_count);
-		if (urb->reject)
-			wake_up (&usb_kill_urb_queue);
+static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
+{
+	if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
+		if (usb_endpoint_xfer_control(&urb->ep->desc)
+			&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
+			dma_unmap_single(hcd->self.controller, urb->setup_dma,
+					sizeof(struct usb_ctrlrequest),
+					DMA_TO_DEVICE);
+		if (urb->transfer_buffer_length != 0
+			&& !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
+			dma_unmap_single(hcd->self.controller,
+					urb->transfer_dma,
+					urb->transfer_buffer_length,
+					usb_urb_dir_in(urb)
+					    ? DMA_FROM_DEVICE
+					    : DMA_TO_DEVICE);
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* may be called in any context with a valid urb->dev usecount
+ * caller surrenders "ownership" of urb
+ * expects usb_submit_urb() to have sanity checked and conditioned all
+ * inputs in the urb
+ */
+int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
+{
+	int			status;
+	struct usb_hcd		*hcd = bus_to_hcd(urb->dev->bus);
+
+	/* increment urb's reference count as part of giving it to the HCD
+	 * (which will control it).  HCD guarantees that it either returns
+	 * an error or calls giveback(), but not both.
+	 */
+	usb_get_urb(urb);
+	atomic_inc(&urb->use_count);
+	atomic_inc(&urb->dev->urbnum);
+	usbmon_urb_submit(&hcd->self, urb);
+
+	/* NOTE requirements on root-hub callers (usbfs and the hub
+	 * driver, for now):  URBs' urb->transfer_buffer must be
+	 * valid and usb_buffer_{sync,unmap}() not be needed, since
+	 * they could clobber root hub response data.  Also, control
+	 * URBs must be submitted in process context with interrupts
+	 * enabled.
+	 */
+	map_urb_for_dma(hcd, urb);
+	if (is_root_hub(urb->dev))
+		status = rh_urb_enqueue(hcd, urb);
+	else
+		status = hcd->driver->urb_enqueue(hcd, urb, mem_flags);
+
+	if (unlikely(status)) {
 		usbmon_urb_submit_error(&hcd->self, urb, status);
-		usb_put_urb (urb);
+		unmap_urb_for_dma(hcd, urb);
+		urb->hcpriv = NULL;
+		INIT_LIST_HEAD(&urb->urb_list);
+		atomic_dec(&urb->use_count);
+		atomic_dec(&urb->dev->urbnum);
+		if (urb->reject)
+			wake_up(&usb_kill_urb_queue);
+		usb_put_urb(urb);
 	}
 	return status;
 }
@@ -1042,24 +1213,19 @@
  * soon as practical.  we've already set up the urb's return status,
  * but we can't know if the callback completed already.
  */
-static int
-unlink1 (struct usb_hcd *hcd, struct urb *urb)
+static int unlink1(struct usb_hcd *hcd, struct urb *urb, int status)
 {
 	int		value;
 
 	if (is_root_hub(urb->dev))
-		value = usb_rh_urb_dequeue (hcd, urb);
+		value = usb_rh_urb_dequeue(hcd, urb, status);
 	else {
 
 		/* The only reason an HCD might fail this call is if
 		 * it has not yet fully queued the urb to begin with.
 		 * Such failures should be harmless. */
-		value = hcd->driver->urb_dequeue (hcd, urb);
+		value = hcd->driver->urb_dequeue(hcd, urb, status);
 	}
-
-	if (value != 0)
-		dev_dbg (hcd->self.controller, "dequeue %p --> %d\n",
-				urb, value);
 	return value;
 }
 
@@ -1071,88 +1237,17 @@
  */
 int usb_hcd_unlink_urb (struct urb *urb, int status)
 {
-	struct usb_host_endpoint	*ep;
-	struct usb_hcd			*hcd = NULL;
-	struct device			*sys = NULL;
-	unsigned long			flags;
-	struct list_head		*tmp;
-	int				retval;
+	struct usb_hcd		*hcd;
+	int			retval;
 
-	if (!urb)
-		return -EINVAL;
-	if (!urb->dev || !urb->dev->bus)
-		return -ENODEV;
-	ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out)
-			[usb_pipeendpoint(urb->pipe)];
-	if (!ep)
-		return -ENODEV;
-
-	/*
-	 * we contend for urb->status with the hcd core,
-	 * which changes it while returning the urb.
-	 *
-	 * Caller guaranteed that the urb pointer hasn't been freed, and
-	 * that it was submitted.  But as a rule it can't know whether or
-	 * not it's already been unlinked ... so we respect the reversed
-	 * lock sequence needed for the usb_hcd_giveback_urb() code paths
-	 * (urb lock, then hcd_urb_list_lock) in case some other CPU is now
-	 * unlinking it.
-	 */
-	spin_lock_irqsave (&urb->lock, flags);
-	spin_lock(&hcd_urb_list_lock);
-
-	sys = &urb->dev->dev;
 	hcd = bus_to_hcd(urb->dev->bus);
-	if (hcd == NULL) {
-		retval = -ENODEV;
-		goto done;
-	}
+	retval = unlink1(hcd, urb, status);
 
-	/* insist the urb is still queued */
-	list_for_each(tmp, &ep->urb_list) {
-		if (tmp == &urb->urb_list)
-			break;
-	}
-	if (tmp != &urb->urb_list) {
-		retval = -EIDRM;
-		goto done;
-	}
-
-	/* Any status except -EINPROGRESS means something already started to
-	 * unlink this URB from the hardware.  So there's no more work to do.
-	 */
-	if (urb->status != -EINPROGRESS) {
-		retval = -EBUSY;
-		goto done;
-	}
-
-	/* IRQ setup can easily be broken so that USB controllers
-	 * never get completion IRQs ... maybe even the ones we need to
-	 * finish unlinking the initial failed usb_set_address()
-	 * or device descriptor fetch.
-	 */
-	if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) &&
-			!is_root_hub(urb->dev)) {
-		dev_warn (hcd->self.controller, "Unlink after no-IRQ?  "
-			"Controller is probably using the wrong IRQ.\n");
-		set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
-	}
-
-	urb->status = status;
-
-	spin_unlock(&hcd_urb_list_lock);
-	spin_unlock_irqrestore (&urb->lock, flags);
-
-	retval = unlink1 (hcd, urb);
 	if (retval == 0)
 		retval = -EINPROGRESS;
-	return retval;
-
-done:
-	spin_unlock(&hcd_urb_list_lock);
-	spin_unlock_irqrestore (&urb->lock, flags);
-	if (retval != -EIDRM && sys && sys->driver)
-		dev_dbg (sys, "hcd_unlink_urb %p fail %d\n", urb, retval);
+	else if (retval != -EIDRM && retval != -EBUSY)
+		dev_dbg(&urb->dev->dev, "hcd_unlink_urb %p fail %d\n",
+				urb, retval);
 	return retval;
 }
 
@@ -1162,6 +1257,7 @@
  * usb_hcd_giveback_urb - return URB from HCD to device driver
  * @hcd: host controller returning the URB
  * @urb: urb being returned to the USB device driver.
+ * @status: completion status code for the URB.
  * Context: in_interrupt()
  *
  * This hands the URB from HCD to its USB device driver, using its
@@ -1169,14 +1265,27 @@
  * (and is done using urb->hcpriv).  It also released all HCD locks;
  * the device driver won't cause problems if it frees, modifies,
  * or resubmits this URB.
+ *
+ * If @urb was unlinked, the value of @status will be overridden by
+ * @urb->unlinked.  Erroneous short transfers are detected in case
+ * the HCD hasn't checked for them.
  */
-void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
+void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status)
 {
-	urb_unlink(hcd, urb);
-	usbmon_urb_complete (&hcd->self, urb);
+	urb->hcpriv = NULL;
+	if (unlikely(urb->unlinked))
+		status = urb->unlinked;
+	else if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
+			urb->actual_length < urb->transfer_buffer_length &&
+			!status))
+		status = -EREMOTEIO;
+
+	unmap_urb_for_dma(hcd, urb);
+	usbmon_urb_complete(&hcd->self, urb, status);
 	usb_unanchor_urb(urb);
 
 	/* pass ownership to the completion handler */
+	urb->status = status;
 	urb->complete (urb);
 	atomic_dec (&urb->use_count);
 	if (unlikely (urb->reject))
@@ -1187,78 +1296,61 @@
 
 /*-------------------------------------------------------------------------*/
 
-/* disables the endpoint: cancels any pending urbs, then synchronizes with
- * the hcd to make sure all endpoint state is gone from hardware, and then
- * waits until the endpoint's queue is completely drained. use for
- * set_configuration, set_interface, driver removal, physical disconnect.
- *
- * example:  a qh stored in ep->hcpriv, holding state related to endpoint
- * type, maxpacket size, toggle, halt status, and scheduling.
+/* Cancel all URBs pending on this endpoint and wait for the endpoint's
+ * queue to drain completely.  The caller must first insure that no more
+ * URBs can be submitted for this endpoint.
  */
-void usb_hcd_endpoint_disable (struct usb_device *udev,
+void usb_hcd_flush_endpoint(struct usb_device *udev,
 		struct usb_host_endpoint *ep)
 {
 	struct usb_hcd		*hcd;
 	struct urb		*urb;
 
+	if (!ep)
+		return;
+	might_sleep();
 	hcd = bus_to_hcd(udev->bus);
-	local_irq_disable ();
 
-	/* ep is already gone from udev->ep_{in,out}[]; no more submits */
+	/* No more submits can occur */
 rescan:
-	spin_lock(&hcd_urb_list_lock);
+	spin_lock_irq(&hcd_urb_list_lock);
 	list_for_each_entry (urb, &ep->urb_list, urb_list) {
-		int	tmp;
+		int	is_in;
 
-		/* the urb may already have been unlinked */
-		if (urb->status != -EINPROGRESS)
+		if (urb->unlinked)
 			continue;
 		usb_get_urb (urb);
+		is_in = usb_urb_dir_in(urb);
 		spin_unlock(&hcd_urb_list_lock);
 
-		spin_lock (&urb->lock);
-		tmp = urb->status;
-		if (tmp == -EINPROGRESS)
-			urb->status = -ESHUTDOWN;
-		spin_unlock (&urb->lock);
+		/* kick hcd */
+		unlink1(hcd, urb, -ESHUTDOWN);
+		dev_dbg (hcd->self.controller,
+			"shutdown urb %p ep%d%s%s\n",
+			urb, usb_endpoint_num(&ep->desc),
+			is_in ? "in" : "out",
+			({	char *s;
 
-		/* kick hcd unless it's already returning this */
-		if (tmp == -EINPROGRESS) {
-			tmp = urb->pipe;
-			unlink1 (hcd, urb);
-			dev_dbg (hcd->self.controller,
-				"shutdown urb %p pipe %08x ep%d%s%s\n",
-				urb, tmp, usb_pipeendpoint (tmp),
-				(tmp & USB_DIR_IN) ? "in" : "out",
-				({ char *s; \
-				 switch (usb_pipetype (tmp)) { \
-				 case PIPE_CONTROL:	s = ""; break; \
-				 case PIPE_BULK:	s = "-bulk"; break; \
-				 case PIPE_INTERRUPT:	s = "-intr"; break; \
-				 default: 		s = "-iso"; break; \
-				}; s;}));
-		}
+				 switch (usb_endpoint_type(&ep->desc)) {
+				 case USB_ENDPOINT_XFER_CONTROL:
+					s = ""; break;
+				 case USB_ENDPOINT_XFER_BULK:
+					s = "-bulk"; break;
+				 case USB_ENDPOINT_XFER_INT:
+					s = "-intr"; break;
+				 default:
+			 		s = "-iso"; break;
+				};
+				s;
+			}));
 		usb_put_urb (urb);
 
 		/* list contents may have changed */
 		goto rescan;
 	}
-	spin_unlock(&hcd_urb_list_lock);
-	local_irq_enable ();
+	spin_unlock_irq(&hcd_urb_list_lock);
 
-	/* synchronize with the hardware, so old configuration state
-	 * clears out immediately (and will be freed).
-	 */
-	might_sleep ();
-	if (hcd->driver->endpoint_disable)
-		hcd->driver->endpoint_disable (hcd, ep);
-
-	/* Wait until the endpoint queue is completely empty.  Most HCDs
-	 * will have done this already in their endpoint_disable method,
-	 * but some might not.  And there could be root-hub control URBs
-	 * still pending since they aren't affected by the HCDs'
-	 * endpoint_disable methods.
-	 */
+	/* Wait until the endpoint queue is completely empty */
 	while (!list_empty (&ep->urb_list)) {
 		spin_lock_irq(&hcd_urb_list_lock);
 
@@ -1278,6 +1370,25 @@
 	}
 }
 
+/* Disables the endpoint: synchronizes with the hcd to make sure all
+ * endpoint state is gone from hardware.  usb_hcd_flush_endpoint() must
+ * have been called previously.  Use for set_configuration, set_interface,
+ * driver removal, physical disconnect.
+ *
+ * example:  a qh stored in ep->hcpriv, holding state related to endpoint
+ * type, maxpacket size, toggle, halt status, and scheduling.
+ */
+void usb_hcd_disable_endpoint(struct usb_device *udev,
+		struct usb_host_endpoint *ep)
+{
+	struct usb_hcd		*hcd;
+
+	might_sleep();
+	hcd = bus_to_hcd(udev->bus);
+	if (hcd->driver->endpoint_disable)
+		hcd->driver->endpoint_disable(hcd, ep);
+}
+
 /*-------------------------------------------------------------------------*/
 
 /* called in any context */
@@ -1525,7 +1636,6 @@
 	hcd->driver = driver;
 	hcd->product_desc = (driver->product_desc) ? driver->product_desc :
 			"USB Host Controller";
-
 	return hcd;
 }
 EXPORT_SYMBOL (usb_create_hcd);
@@ -1570,6 +1680,7 @@
 
 	dev_info(hcd->self.controller, "%s\n", hcd->product_desc);
 
+	hcd->authorized_default = hcd->wireless? 0 : 1;
 	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
 
 	/* HC is in reset state, but accessible.  Now do the one-time init,
@@ -1646,10 +1757,20 @@
 	if ((retval = register_root_hub(hcd)) != 0)
 		goto err_register_root_hub;
 
+	retval = sysfs_create_group(&rhdev->dev.kobj, &usb_bus_attr_group);
+	if (retval < 0) {
+		printk(KERN_ERR "Cannot register USB bus sysfs attributes: %d\n",
+		       retval);
+		goto error_create_attr_group;
+	}
 	if (hcd->uses_new_polling && hcd->poll_rh)
 		usb_hcd_poll_rh_status(hcd);
 	return retval;
 
+error_create_attr_group:
+	mutex_lock(&usb_bus_list_lock);
+	usb_disconnect(&hcd->self.root_hub);
+	mutex_unlock(&usb_bus_list_lock);
 err_register_root_hub:
 	hcd->driver->stop(hcd);
 err_hcd_driver_start:
@@ -1691,6 +1812,7 @@
 	cancel_work_sync(&hcd->wakeup_work);
 #endif
 
+	sysfs_remove_group(&hcd->self.root_hub->dev.kobj, &usb_bus_attr_group);
 	mutex_lock(&usb_bus_list_lock);
 	usb_disconnect(&hcd->self.root_hub);
 	mutex_unlock(&usb_bus_list_lock);
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index b5ebb73..98e2419 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -19,6 +19,8 @@
 
 #ifdef __KERNEL__
 
+#include <linux/rwsem.h>
+
 /* This file contains declarations of usbcore internals that are mostly
  * used or exposed by Host Controller Drivers.
  */
@@ -51,6 +53,12 @@
  *
  * Since "struct usb_bus" is so thin, you can't share much code in it.
  * This framework is a layer over that, and should be more sharable.
+ *
+ * @authorized_default: Specifies if new devices are authorized to
+ *                      connect by default or they require explicit
+ *                      user space authorization; this bit is settable
+ *                      through /sys/class/usb_host/X/authorized_default.
+ *                      For the rest is RO, so we don't lock to r/w it.
  */
 
 /*-------------------------------------------------------------------------*/
@@ -90,6 +98,7 @@
 	unsigned		poll_rh:1;	/* poll for rh status? */
 	unsigned		poll_pending:1;	/* status has changed? */
 	unsigned		wireless:1;	/* Wireless USB HCD */
+	unsigned		authorized_default:1;
 
 	int			irq;		/* irq allocated */
 	void __iomem		*regs;		/* device memory/io */
@@ -182,11 +191,10 @@
 	int	(*get_frame_number) (struct usb_hcd *hcd);
 
 	/* manage i/o requests, device state */
-	int	(*urb_enqueue) (struct usb_hcd *hcd,
-					struct usb_host_endpoint *ep,
-					struct urb *urb,
-					gfp_t mem_flags);
-	int	(*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb);
+	int	(*urb_enqueue)(struct usb_hcd *hcd,
+				struct urb *urb, gfp_t mem_flags);
+	int	(*urb_dequeue)(struct usb_hcd *hcd,
+				struct urb *urb, int status);
 
 	/* hw synch, freeing endpoint resources that urb_dequeue can't */
 	void 	(*endpoint_disable)(struct usb_hcd *hcd,
@@ -204,10 +212,18 @@
 		/* Needed only if port-change IRQs are level-triggered */
 };
 
+extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
+extern int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
+		int status);
+extern void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb);
+
 extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags);
 extern int usb_hcd_unlink_urb (struct urb *urb, int status);
-extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb);
-extern void usb_hcd_endpoint_disable (struct usb_device *udev,
+extern void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb,
+		int status);
+extern void usb_hcd_flush_endpoint(struct usb_device *udev,
+		struct usb_host_endpoint *ep);
+extern void usb_hcd_disable_endpoint(struct usb_device *udev,
 		struct usb_host_endpoint *ep);
 extern int usb_hcd_get_frame_number (struct usb_device *udev);
 
@@ -402,7 +418,7 @@
 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_complete)(struct usb_bus *bus, struct urb *urb, int status);
 	/* void (*urb_unlink)(struct usb_bus *bus, struct urb *urb); */
 };
 
@@ -421,10 +437,11 @@
 		(*mon_ops->urb_submit_error)(bus, urb, error);
 }
 
-static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb)
+static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
+		int status)
 {
 	if (bus->monitored)
-		(*mon_ops->urb_complete)(bus, urb);
+		(*mon_ops->urb_complete)(bus, urb, status);
 }
 
 int usb_mon_register(struct usb_mon_operations *ops);
@@ -435,7 +452,8 @@
 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_urb_complete(struct usb_bus *bus, struct urb *urb,
+		int status) {}
 
 #endif /* CONFIG_USB_MON */
 
@@ -454,5 +472,9 @@
 		: (in_interrupt () ? "in_interrupt" : "can sleep"))
 
 
-#endif /* __KERNEL__ */
+/* This rwsem is for use only by the hub driver and ehci-hcd.
+ * Nobody else should touch it.
+ */
+extern struct rw_semaphore ehci_cf_port_reset_rwsem;
 
+#endif /* __KERNEL__ */
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index f7b337f..d20cb54 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -125,6 +125,12 @@
 		"try the other device initialization scheme if the "
 		"first one fails");
 
+/* Mutual exclusion for EHCI CF initialization.  This interferes with
+ * port reset on some companion controllers.
+ */
+DECLARE_RWSEM(ehci_cf_port_reset_rwsem);
+EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem);
+
 
 static inline char *portspeed(int portstatus)
 {
@@ -347,11 +353,11 @@
 static void hub_irq(struct urb *urb)
 {
 	struct usb_hub *hub = urb->context;
-	int status;
+	int status = urb->status;
 	int i;
 	unsigned long bits;
 
-	switch (urb->status) {
+	switch (status) {
 	case -ENOENT:		/* synchronous unlink */
 	case -ECONNRESET:	/* async unlink */
 	case -ESHUTDOWN:	/* hardware going away */
@@ -359,10 +365,10 @@
 
 	default:		/* presumably an error */
 		/* Cause a hub reset after 10 consecutive errors */
-		dev_dbg (hub->intfdev, "transfer --> %d\n", urb->status);
+		dev_dbg (hub->intfdev, "transfer --> %d\n", status);
 		if ((++hub->nerrors < 10) || hub->error)
 			goto resubmit;
-		hub->error = urb->status;
+		hub->error = status;
 		/* FALL THROUGH */
 
 	/* let khubd handle things */
@@ -1220,54 +1226,14 @@
 #endif
 
 /**
- * usb_new_device - perform initial device setup (usbcore-internal)
+ * usb_configure_device_otg - FIXME (usbcore-internal)
  * @udev: newly addressed device (in ADDRESS state)
  *
- * This is called with devices which have been enumerated, but not yet
- * configured.  The device descriptor is available, but not descriptors
- * for any device configuration.  The caller must have locked either
- * the parent hub (if udev is a normal device) or else the
- * usb_bus_list_lock (if udev is a root hub).  The parent's pointer to
- * udev has already been installed, but udev is not yet visible through
- * sysfs or other filesystem code.
- *
- * It will return if the device is configured properly or not.  Zero if
- * the interface was registered with the driver core; else a negative
- * errno value.
- *
- * This call is synchronous, and may not be used in an interrupt context.
- *
- * Only the hub driver or root-hub registrar should ever call this.
+ * Do configuration for On-The-Go devices
  */
-int usb_new_device(struct usb_device *udev)
+static int usb_configure_device_otg(struct usb_device *udev)
 {
-	int err;
-
-	/* Determine quirks */
-	usb_detect_quirks(udev);
-
-	err = usb_get_configuration(udev);
-	if (err < 0) {
-		dev_err(&udev->dev, "can't read configurations, error %d\n",
-			err);
-		goto fail;
-	}
-
-	/* read the standard strings and cache them if present */
-	udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
-	udev->manufacturer = usb_cache_string(udev,
-			udev->descriptor.iManufacturer);
-	udev->serial = usb_cache_string(udev, 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);
-	show_string(udev, "Product", udev->product);
-	show_string(udev, "Manufacturer", udev->manufacturer);
-	show_string(udev, "SerialNumber", udev->serial);
+	int err = 0;
 
 #ifdef	CONFIG_USB_OTG
 	/*
@@ -1329,8 +1295,82 @@
 		err = -ENOTSUPP;
 		goto fail;
 	}
+fail:
 #endif
+	return err;
+}
 
+
+/**
+ * usb_configure_device - Detect and probe device intfs/otg (usbcore-internal)
+ * @udev: newly addressed device (in ADDRESS state)
+ *
+ * This is only called by usb_new_device() and usb_authorize_device()
+ * and FIXME -- all comments that apply to them apply here wrt to
+ * environment.
+ *
+ * If the device is WUSB and not authorized, we don't attempt to read
+ * the string descriptors, as they will be errored out by the device
+ * until it has been authorized.
+ */
+static int usb_configure_device(struct usb_device *udev)
+{
+	int err;
+
+	if (udev->config == NULL) {
+		err = usb_get_configuration(udev);
+		if (err < 0) {
+			dev_err(&udev->dev, "can't read configurations, error %d\n",
+				err);
+			goto fail;
+		}
+	}
+	if (udev->wusb == 1 && udev->authorized == 0) {
+		udev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+		udev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+		udev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+	}
+	else {
+		/* read the standard strings and cache them if present */
+		udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
+		udev->manufacturer = usb_cache_string(udev,
+						      udev->descriptor.iManufacturer);
+		udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
+	}
+	err = usb_configure_device_otg(udev);
+fail:
+	return err;
+}
+
+
+/**
+ * usb_new_device - perform initial device setup (usbcore-internal)
+ * @udev: newly addressed device (in ADDRESS state)
+ *
+ * This is called with devices which have been enumerated, but not yet
+ * configured.  The device descriptor is available, but not descriptors
+ * for any device configuration.  The caller must have locked either
+ * the parent hub (if udev is a normal device) or else the
+ * usb_bus_list_lock (if udev is a root hub).  The parent's pointer to
+ * udev has already been installed, but udev is not yet visible through
+ * sysfs or other filesystem code.
+ *
+ * It will return if the device is configured properly or not.  Zero if
+ * the interface was registered with the driver core; else a negative
+ * errno value.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * Only the hub driver or root-hub registrar should ever call this.
+ */
+int usb_new_device(struct usb_device *udev)
+{
+	int err;
+
+	usb_detect_quirks(udev);		/* Determine quirks */
+	err = usb_configure_device(udev);	/* detect & probe dev/intfs */
+	if (err < 0)
+		goto fail;
 	/* export the usbdev device-node for libusb */
 	udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
 			(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
@@ -1346,19 +1386,106 @@
 	err = device_add(&udev->dev);
 	if (err) {
 		dev_err(&udev->dev, "can't device_add, error %d\n", err);
-		if (udev->parent)
-			usb_autosuspend_device(udev->parent);
 		goto fail;
 	}
 
-exit:
+	/* 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);
+	show_string(udev, "Product", udev->product);
+	show_string(udev, "Manufacturer", udev->manufacturer);
+	show_string(udev, "SerialNumber", udev->serial);
 	return err;
 
 fail:
 	usb_set_device_state(udev, USB_STATE_NOTATTACHED);
-	goto exit;
+	return err;
 }
 
+
+/**
+ * Similar to usb_disconnect()
+ *
+ * We share a lock (that we have) with device_del(), so we need to
+ * defer its call.
+ */
+int usb_deauthorize_device(struct usb_device *usb_dev)
+{
+	unsigned cnt;
+	usb_lock_device(usb_dev);
+	if (usb_dev->authorized == 0)
+		goto out_unauthorized;
+	usb_dev->authorized = 0;
+	usb_set_configuration(usb_dev, -1);
+	usb_dev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+	usb_dev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+	usb_dev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+	kfree(usb_dev->config);
+	usb_dev->config = NULL;
+	for (cnt = 0; cnt < usb_dev->descriptor.bNumConfigurations; cnt++)
+		kfree(usb_dev->rawdescriptors[cnt]);
+	usb_dev->descriptor.bNumConfigurations = 0;
+	kfree(usb_dev->rawdescriptors);
+out_unauthorized:
+	usb_unlock_device(usb_dev);
+	return 0;
+}
+
+
+int usb_authorize_device(struct usb_device *usb_dev)
+{
+	int result = 0, c;
+	usb_lock_device(usb_dev);
+	if (usb_dev->authorized == 1)
+		goto out_authorized;
+	kfree(usb_dev->product);
+	usb_dev->product = NULL;
+	kfree(usb_dev->manufacturer);
+	usb_dev->manufacturer = NULL;
+	kfree(usb_dev->serial);
+	usb_dev->serial = NULL;
+	result = usb_autoresume_device(usb_dev);
+	if (result < 0) {
+		dev_err(&usb_dev->dev,
+			"can't autoresume for authorization: %d\n", result);
+		goto error_autoresume;
+	}
+	result = usb_get_device_descriptor(usb_dev, sizeof(usb_dev->descriptor));
+	if (result < 0) {
+		dev_err(&usb_dev->dev, "can't re-read device descriptor for "
+			"authorization: %d\n", result);
+		goto error_device_descriptor;
+	}
+	usb_dev->authorized = 1;
+	result = usb_configure_device(usb_dev);
+	if (result < 0)
+		goto error_configure;
+	/* Choose and set the configuration.  This registers the interfaces
+	 * with the driver core and lets interface drivers bind to them.
+	 */
+	c = usb_choose_configuration(usb_dev);
+	if (c >= 0) {
+		result = usb_set_configuration(usb_dev, c);
+		if (result) {
+			dev_err(&usb_dev->dev,
+				"can't set config #%d, error %d\n", c, result);
+			/* This need not be fatal.  The user can try to
+			 * set other configurations. */
+		}
+	}
+	dev_info(&usb_dev->dev, "authorized to connect\n");
+error_configure:
+error_device_descriptor:
+error_autoresume:
+out_authorized:
+	usb_unlock_device(usb_dev);	// complements locktree
+	return result;
+}
+
+
 static int hub_port_status(struct usb_hub *hub, int port1,
 			       u16 *status, u16 *change)
 {
@@ -1460,6 +1587,11 @@
 {
 	int i, status;
 
+	/* Block EHCI CF initialization during the port reset.
+	 * Some companion controllers don't like it when they mix.
+	 */
+	down_read(&ehci_cf_port_reset_rwsem);
+
 	/* Reset the port */
 	for (i = 0; i < PORT_RESET_TRIES; i++) {
 		status = set_port_feature(hub->hdev,
@@ -1481,6 +1613,7 @@
 		case 0:
 			/* TRSTRCY = 10 ms; plus some extra */
 			msleep(10 + 40);
+		  	udev->devnum = 0;	/* Device now at address 0 */
 			/* FALL THROUGH */
 		case -ENOTCONN:
 		case -ENODEV:
@@ -1490,7 +1623,7 @@
 			usb_set_device_state(udev, status
 					? USB_STATE_NOTATTACHED
 					: USB_STATE_DEFAULT);
-			return status;
+			goto done;
 		}
 
 		dev_dbg (hub->intfdev,
@@ -1503,6 +1636,8 @@
 		"Cannot enable port %i.  Maybe the USB cable is bad?\n",
 		port1);
 
+ done:
+	up_read(&ehci_cf_port_reset_rwsem);
 	return status;
 }
 
@@ -1833,14 +1968,7 @@
 		struct usb_device	*udev;
 
 		udev = hdev->children [port1-1];
-		if (udev && msg.event == PM_EVENT_SUSPEND &&
-#ifdef	CONFIG_USB_SUSPEND
-				udev->state != USB_STATE_SUSPENDED
-#else
-				udev->dev.power.power_state.event
-					== PM_EVENT_ON
-#endif
-				) {
+		if (udev && udev->can_submit) {
 			if (!hdev->auto_pm)
 				dev_dbg(&intf->dev, "port %d nyet suspended\n",
 						port1);
@@ -1999,26 +2127,27 @@
 {
 	usb_disable_endpoint(udev, 0 + USB_DIR_IN);
 	usb_disable_endpoint(udev, 0 + USB_DIR_OUT);
-	udev->ep_in[0] = udev->ep_out[0] = &udev->ep0;
+	usb_enable_endpoint(udev, &udev->ep0);
 }
 
 #define usb_sndaddr0pipe()	(PIPE_CONTROL << 30)
 #define usb_rcvaddr0pipe()	((PIPE_CONTROL << 30) | USB_DIR_IN)
 
-static int hub_set_address(struct usb_device *udev)
+static int hub_set_address(struct usb_device *udev, int devnum)
 {
 	int retval;
 
-	if (udev->devnum == 0)
+	if (devnum <= 1)
 		return -EINVAL;
 	if (udev->state == USB_STATE_ADDRESS)
 		return 0;
 	if (udev->state != USB_STATE_DEFAULT)
 		return -EINVAL;
 	retval = usb_control_msg(udev, usb_sndaddr0pipe(),
-		USB_REQ_SET_ADDRESS, 0, udev->devnum, 0,
+		USB_REQ_SET_ADDRESS, 0, devnum, 0,
 		NULL, 0, USB_CTRL_SET_TIMEOUT);
 	if (retval == 0) {
+		udev->devnum = devnum;	/* Device now using proper address */
 		usb_set_device_state(udev, USB_STATE_ADDRESS);
 		ep0_reinit(udev);
 	}
@@ -2045,6 +2174,7 @@
 	unsigned		delay = HUB_SHORT_RESET_TIME;
 	enum usb_device_speed	oldspeed = udev->speed;
 	char 			*speed, *type;
+	int			devnum = udev->devnum;
 
 	/* root hub ports have a slightly longer reset period
 	 * (from USB 2.0 spec, section 7.1.7.5)
@@ -2074,7 +2204,7 @@
 		goto fail;
 	}
 	oldspeed = udev->speed;
-  
+
 	/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
 	 * it's fixed size except for full speed devices.
 	 * For Wireless USB devices, ep0 max packet is always 512 (tho
@@ -2115,7 +2245,7 @@
 	dev_info (&udev->dev,
 		  "%s %s speed %sUSB device using %s and address %d\n",
 		  (udev->config) ? "reset" : "new", speed, type,
-		  udev->bus->controller->driver->name, udev->devnum);
+		  udev->bus->controller->driver->name, devnum);
 
 	/* Set up TT records, if needed  */
 	if (hdev->tt) {
@@ -2202,7 +2332,7 @@
 		}
 
 		for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
-			retval = hub_set_address(udev);
+			retval = hub_set_address(udev, devnum);
 			if (retval >= 0)
 				break;
 			msleep(200);
@@ -2210,7 +2340,7 @@
 		if (retval < 0) {
 			dev_err(&udev->dev,
 				"device not accepting address %d, error %d\n",
-				udev->devnum, retval);
+				devnum, retval);
 			goto fail;
 		}
  
@@ -2263,8 +2393,10 @@
 	retval = 0;
 
 fail:
-	if (retval)
+	if (retval) {
 		hub_port_disable(hub, port1, 0);
+		udev->devnum = devnum;	/* for disconnect processing */
+	}
 	mutex_unlock(&usb_address0_mutex);
 	return retval;
 }
@@ -2699,9 +2831,9 @@
 				clear_hub_feature(hdev, C_HUB_LOCAL_POWER);
 				if (hubstatus & HUB_STATUS_LOCAL_POWER)
 					/* FIXME: Is this always true? */
-					hub->limited_power = 0;
-				else
 					hub->limited_power = 1;
+				else
+					hub->limited_power = 0;
 			}
 			if (hubchange & HUB_CHANGE_OVERCURRENT) {
 				dev_dbg (hub_dev, "overcurrent change\n");
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index d8f7b08..c021af3 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -59,8 +59,8 @@
 		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",
+			usb_endpoint_num(&urb->ep->desc),
+			usb_urb_dir_in(urb) ? "in" : "out",
 			urb->actual_length,
 			urb->transfer_buffer_length);
 	} else
@@ -250,7 +250,8 @@
 		io->urbs = NULL;
 	}
 	if (io->dev->dev.dma_mask != NULL)
-		usb_buffer_unmap_sg (io->dev, io->pipe, io->sg, io->nents);
+		usb_buffer_unmap_sg (io->dev, usb_pipein(io->pipe),
+				io->sg, io->nents);
 	io->dev = NULL;
 }
 
@@ -278,8 +279,8 @@
 		dev_err (io->dev->bus->controller,
 			"dev %s ep%d%s scatterlist error %d/%d\n",
 			io->dev->devpath,
-			usb_pipeendpoint (urb->pipe),
-			usb_pipein (urb->pipe) ? "in" : "out",
+			usb_endpoint_num(&urb->ep->desc),
+			usb_urb_dir_in(urb) ? "in" : "out",
 			status, io->status);
 		// BUG ();
 	}
@@ -379,7 +380,8 @@
 	 */
 	dma = (dev->dev.dma_mask != NULL);
 	if (dma)
-		io->entries = usb_buffer_map_sg (dev, pipe, sg, nents);
+		io->entries = usb_buffer_map_sg(dev, usb_pipein(pipe),
+				sg, nents);
 	else
 		io->entries = nents;
 
@@ -1013,8 +1015,11 @@
 		ep = dev->ep_in[epnum];
 		dev->ep_in[epnum] = NULL;
 	}
-	if (ep && dev->bus)
-		usb_hcd_endpoint_disable(dev, ep);
+	if (ep) {
+		ep->enabled = 0;
+		usb_hcd_flush_endpoint(dev, ep);
+		usb_hcd_disable_endpoint(dev, ep);
+	}
 }
 
 /**
@@ -1096,23 +1101,21 @@
  * Resets the endpoint toggle, and sets dev->ep_{in,out} pointers.
  * For control endpoints, both the input and output sides are handled.
  */
-static void
-usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep)
+void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep)
 {
-	unsigned int epaddr = ep->desc.bEndpointAddress;
-	unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK;
-	int is_control;
+	int epnum = usb_endpoint_num(&ep->desc);
+	int is_out = usb_endpoint_dir_out(&ep->desc);
+	int is_control = usb_endpoint_xfer_control(&ep->desc);
 
-	is_control = ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-			== USB_ENDPOINT_XFER_CONTROL);
-	if (usb_endpoint_out(epaddr) || is_control) {
+	if (is_out || is_control) {
 		usb_settoggle(dev, epnum, 1, 0);
 		dev->ep_out[epnum] = ep;
 	}
-	if (!usb_endpoint_out(epaddr) || is_control) {
+	if (!is_out || is_control) {
 		usb_settoggle(dev, epnum, 0, 0);
 		dev->ep_in[epnum] = ep;
 	}
+	ep->enabled = 1;
 }
 
 /*
@@ -1171,6 +1174,7 @@
 	struct usb_host_interface *alt;
 	int ret;
 	int manual = 0;
+	int changed;
 
 	if (dev->state == USB_STATE_SUSPENDED)
 		return -EHOSTUNREACH;
@@ -1210,7 +1214,8 @@
 	 */
 
 	/* prevent submissions using previous endpoint settings */
-	if (device_is_registered(&iface->dev))
+	changed = (iface->cur_altsetting != alt);
+	if (changed && device_is_registered(&iface->dev))
 		usb_remove_sysfs_intf_files(iface);
 	usb_disable_interface(dev, iface);
 
@@ -1247,7 +1252,7 @@
 	 * (Likewise, EP0 never "halts" on well designed devices.)
 	 */
 	usb_enable_interface(dev, iface);
-	if (device_is_registered(&iface->dev))
+	if (changed && device_is_registered(&iface->dev))
 		usb_create_sysfs_intf_files(iface);
 
 	return 0;
@@ -1328,7 +1333,7 @@
 	return 0;
 }
 
-void usb_release_interface(struct device *dev)
+static void usb_release_interface(struct device *dev)
 {
 	struct usb_interface *intf = to_usb_interface(dev);
 	struct usb_interface_cache *intfc =
@@ -1339,14 +1344,11 @@
 }
 
 #ifdef	CONFIG_HOTPLUG
-static int usb_if_uevent(struct device *dev, char **envp, int num_envp,
-		 char *buffer, int buffer_size)
+static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct usb_device *usb_dev;
 	struct usb_interface *intf;
 	struct usb_host_interface *alt;
-	int i = 0;
-	int length = 0;
 
 	if (!dev)
 		return -ENODEV;
@@ -1359,39 +1361,30 @@
 	alt = intf->cur_altsetting;
 
 #ifdef CONFIG_USB_DEVICEFS
-	if (add_uevent_var(envp, num_envp, &i,
-			   buffer, buffer_size, &length,
-			   "DEVICE=/proc/bus/usb/%03d/%03d",
+	if (add_uevent_var(env, "DEVICE=/proc/bus/usb/%03d/%03d",
 			   usb_dev->bus->busnum, usb_dev->devnum))
 		return -ENOMEM;
 #endif
 
-	if (add_uevent_var(envp, num_envp, &i,
-			   buffer, buffer_size, &length,
-			   "PRODUCT=%x/%x/%x",
+	if (add_uevent_var(env, "PRODUCT=%x/%x/%x",
 			   le16_to_cpu(usb_dev->descriptor.idVendor),
 			   le16_to_cpu(usb_dev->descriptor.idProduct),
 			   le16_to_cpu(usb_dev->descriptor.bcdDevice)))
 		return -ENOMEM;
 
-	if (add_uevent_var(envp, num_envp, &i,
-			   buffer, buffer_size, &length,
-			   "TYPE=%d/%d/%d",
+	if (add_uevent_var(env, "TYPE=%d/%d/%d",
 			   usb_dev->descriptor.bDeviceClass,
 			   usb_dev->descriptor.bDeviceSubClass,
 			   usb_dev->descriptor.bDeviceProtocol))
 		return -ENOMEM;
 
-	if (add_uevent_var(envp, num_envp, &i,
-		   buffer, buffer_size, &length,
-		   "INTERFACE=%d/%d/%d",
+	if (add_uevent_var(env, "INTERFACE=%d/%d/%d",
 		   alt->desc.bInterfaceClass,
 		   alt->desc.bInterfaceSubClass,
 		   alt->desc.bInterfaceProtocol))
 		return -ENOMEM;
 
-	if (add_uevent_var(envp, num_envp, &i,
-		   buffer, buffer_size, &length,
+	if (add_uevent_var(env,
 		   "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),
@@ -1404,14 +1397,12 @@
 		   alt->desc.bInterfaceProtocol))
 		return -ENOMEM;
 
-	envp[i] = NULL;
 	return 0;
 }
 
 #else
 
-static int usb_if_uevent(struct device *dev, char **envp,
-			 int num_envp, char *buffer, int buffer_size)
+static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	return -ENODEV;
 }
@@ -1481,6 +1472,9 @@
  * channels are available independently; and choosing between open
  * standard device protocols (like CDC) or proprietary ones.
  *
+ * Note that a non-authorized device (dev->authorized == 0) will only
+ * be put in unconfigured mode.
+ *
  * Note that USB has an additional level of device configurability,
  * associated with interfaces.  That configurability is accessed using
  * usb_set_interface().
@@ -1502,7 +1496,7 @@
 	struct usb_interface **new_interfaces = NULL;
 	int n, nintf;
 
-	if (configuration == -1)
+	if (dev->authorized == 0 || configuration == -1)
 		configuration = 0;
 	else {
 		for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index ebf3dc2..d42c561 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -32,52 +32,6 @@
 	{ USB_DEVICE(0x0204, 0x6025), .driver_info = USB_QUIRK_RESET_RESUME },
 	/* HP 5300/5370C scanner */
 	{ USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 },
-	/* Hewlett-Packard PhotoSmart 720 / PhotoSmart 935 (storage) */
-	{ USB_DEVICE(0x03f0, 0x4002), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
-	/* SGS Thomson Microelectronics 4in1 card reader */
-	{ USB_DEVICE(0x0483, 0x0321), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
-	/* Acer Peripherals Inc. (now BenQ Corp.) Prisa 640BU */
-	{ USB_DEVICE(0x04a5, 0x207e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* Benq S2W 3300U */
-	{ USB_DEVICE(0x04a5, 0x20b0), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* Canon, Inc. CanoScan N1240U/LiDE30 */
-	{ USB_DEVICE(0x04a9, 0x220e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* Canon, Inc. CanoScan N650U/N656U */
-	{ USB_DEVICE(0x04a9, 0x2206), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* Canon, Inc. CanoScan 1220U */
-	{ USB_DEVICE(0x04a9, 0x2207), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* Canon, Inc. CanoScan N670U/N676U/LiDE 20 */
-	{ USB_DEVICE(0x04a9, 0x220d), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* old Cannon scanner */
-	{ USB_DEVICE(0x04a9, 0x2220), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* Seiko Epson Corp. Perfection 1200 */
-	{ USB_DEVICE(0x04b8, 0x0104), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* Seiko Epson Corp. Perfection 660 */
-	{ USB_DEVICE(0x04b8, 0x0114), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* Epson Perfection 1260 Photo */
-	{ USB_DEVICE(0x04b8, 0x011d), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* Seiko Epson Corp - Perfection 1670 */
-	{ USB_DEVICE(0x04b8, 0x011f), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* EPSON Perfection 2480 */
-	{ USB_DEVICE(0x04b8, 0x0121), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* Seiko Epson Corp.*/
-	{ USB_DEVICE(0x04b8, 0x0122), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* Samsung ML-2010 printer */
-	{ USB_DEVICE(0x04e8, 0x326c), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* Samsung ML-2510 Series printer */
-	{ USB_DEVICE(0x04e8, 0x327e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* Elsa MicroLink 56k (V.250) */
-	{ USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* Ultima Electronics Corp.*/
-	{ USB_DEVICE(0x05d8, 0x4005), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
-	/* Genesys USB-to-IDE */
-	{ USB_DEVICE(0x0503, 0x0702), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
-	/* USB Graphical LCD - EEH Datalink GmbH */
-	{ USB_DEVICE(0x060c, 0x04eb), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
 
 	/* INTEL VALUE SSD */
 	{ USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME },
@@ -85,44 +39,15 @@
 	/* M-Systems Flash Disk Pioneers */
 	{ USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
 
-	/* Agfa Snapscan1212u */
-	{ USB_DEVICE(0x06bd, 0x2061), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* Seagate RSS LLC */
-	{ USB_DEVICE(0x0bc2, 0x3000), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* Umax [hex] Astra 3400U */
-	{ USB_DEVICE(0x1606, 0x0060), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
 	/* Philips PSC805 audio device */
 	{ USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME },
 
-	/* Alcor multi-card reader */
-	{ USB_DEVICE(0x058f, 0x6366), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
-	/* Canon EOS 5D in PC Connection mode */
-	{ USB_DEVICE(0x04a9, 0x3101), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
-	/* RIM Blackberry */
-	{ USB_DEVICE(0x0fca, 0x0001), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	{ USB_DEVICE(0x0fca, 0x0004), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	{ USB_DEVICE(0x0fca, 0x0006), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
-	/* Apple iPhone */
-	{ USB_DEVICE(0x05ac, 0x1290), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
 	/* SKYMEDI USB_DRIVE */
 	{ USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME },
 
 	{ }  /* terminating entry must be last */
 };
 
-static void usb_autosuspend_quirk(struct usb_device *udev)
-{
-#ifdef	CONFIG_USB_SUSPEND
-	/* disable autosuspend, but allow the user to re-enable it via sysfs */
-	udev->autosuspend_disabled = 1;
-#endif
-}
-
 static const struct usb_device_id *find_id(struct usb_device *udev)
 {
 	const struct usb_device_id *id = usb_quirk_list;
@@ -149,13 +74,9 @@
 		dev_dbg(&udev->dev, "USB quirks for this device: %x\n",
 				udev->quirks);
 
-	/* do any special quirk handling here if needed */
-	if (udev->quirks & USB_QUIRK_NO_AUTOSUSPEND)
-		usb_autosuspend_quirk(udev);
-
 	/* By default, disable autosuspend for all non-hubs */
 #ifdef	CONFIG_USB_SUSPEND
 	if (udev->descriptor.bDeviceClass != USB_CLASS_HUB)
-		udev->autosuspend_delay = -1;
+		udev->autosuspend_disabled = 1;
 #endif
 }
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 2ab222b..b04afd0 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -169,6 +169,16 @@
 }
 static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL);
 
+static ssize_t
+show_urbnum(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct usb_device *udev;
+
+	udev = to_usb_device(dev);
+	return sprintf(buf, "%d\n", atomic_read(&udev->urbnum));
+}
+static DEVICE_ATTR(urbnum, S_IRUGO, show_urbnum, NULL);
+
 
 #if defined(CONFIG_USB_PERSIST) || defined(CONFIG_USB_SUSPEND)
 static const char power_group[] = "power";
@@ -413,6 +423,44 @@
 usb_descriptor_attr(bNumConfigurations, "%d\n")
 usb_descriptor_attr(bMaxPacketSize0, "%d\n")
 
+
+
+/* show if the device is authorized (1) or not (0) */
+static ssize_t usb_dev_authorized_show(struct device *dev,
+				       struct device_attribute *attr,
+				       char *buf)
+{
+	struct usb_device *usb_dev = to_usb_device(dev);
+	return snprintf(buf, PAGE_SIZE, "%u\n", usb_dev->authorized);
+}
+
+
+/*
+ * Authorize a device to be used in the system
+ *
+ * Writing a 0 deauthorizes the device, writing a 1 authorizes it.
+ */
+static ssize_t usb_dev_authorized_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t size)
+{
+	ssize_t result;
+	struct usb_device *usb_dev = to_usb_device(dev);
+	unsigned val;
+	result = sscanf(buf, "%u\n", &val);
+	if (result != 1)
+		result = -EINVAL;
+	else if (val == 0)
+		result = usb_deauthorize_device(usb_dev);
+	else
+		result = usb_authorize_device(usb_dev);
+	return result < 0? result : size;
+}
+
+static DEVICE_ATTR(authorized, 0644,
+	    usb_dev_authorized_show, usb_dev_authorized_store);
+
+
 static struct attribute *dev_attrs[] = {
 	/* current configuration's attributes */
 	&dev_attr_configuration.attr,
@@ -420,6 +468,7 @@
 	&dev_attr_bConfigurationValue.attr,
 	&dev_attr_bmAttributes.attr,
 	&dev_attr_bMaxPower.attr,
+	&dev_attr_urbnum.attr,
 	/* device attributes */
 	&dev_attr_idVendor.attr,
 	&dev_attr_idProduct.attr,
@@ -435,6 +484,7 @@
 	&dev_attr_version.attr,
 	&dev_attr_maxchild.attr,
 	&dev_attr_quirks.attr,
+	&dev_attr_authorized.attr,
 	NULL,
 };
 static struct attribute_group dev_attr_grp = {
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index be63022..c20c03a 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -3,6 +3,7 @@
 #include <linux/bitops.h>
 #include <linux/slab.h>
 #include <linux/init.h>
+#include <linux/log2.h>
 #include <linux/usb.h>
 #include <linux/wait.h>
 #include "hcd.h"
@@ -38,7 +39,6 @@
 	if (urb) {
 		memset(urb, 0, sizeof(*urb));
 		kref_init(&urb->kref);
-		spin_lock_init(&urb->lock);
 		INIT_LIST_HEAD(&urb->anchor_list);
 	}
 }
@@ -277,44 +277,58 @@
  */
 int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
 {
-	int			pipe, temp, max;
-	struct usb_device	*dev;
-	int			is_out;
+	int				xfertype, max;
+	struct usb_device		*dev;
+	struct usb_host_endpoint	*ep;
+	int				is_out;
 
 	if (!urb || urb->hcpriv || !urb->complete)
 		return -EINVAL;
-	if (!(dev = urb->dev) ||
-	    (dev->state < USB_STATE_DEFAULT) ||
-	    (!dev->bus) || (dev->devnum <= 0))
+	if (!(dev = urb->dev) || dev->state < USB_STATE_DEFAULT)
 		return -ENODEV;
-	if (dev->bus->controller->power.power_state.event != PM_EVENT_ON
-			|| dev->state == USB_STATE_SUSPENDED)
-		return -EHOSTUNREACH;
 
+	/* For now, get the endpoint from the pipe.  Eventually drivers
+	 * will be required to set urb->ep directly and we will eliminate
+	 * urb->pipe.
+	 */
+	ep = (usb_pipein(urb->pipe) ? dev->ep_in : dev->ep_out)
+			[usb_pipeendpoint(urb->pipe)];
+	if (!ep)
+		return -ENOENT;
+
+	urb->ep = ep;
 	urb->status = -EINPROGRESS;
 	urb->actual_length = 0;
 
 	/* Lots of sanity checks, so HCDs can rely on clean data
 	 * and don't need to duplicate tests
 	 */
-	pipe = urb->pipe;
-	temp = usb_pipetype(pipe);
-	is_out = usb_pipeout(pipe);
+	xfertype = usb_endpoint_type(&ep->desc);
+	if (xfertype == USB_ENDPOINT_XFER_CONTROL) {
+		struct usb_ctrlrequest *setup =
+				(struct usb_ctrlrequest *) urb->setup_packet;
 
-	if (!usb_pipecontrol(pipe) && dev->state < USB_STATE_CONFIGURED)
+		if (!setup)
+			return -ENOEXEC;
+		is_out = !(setup->bRequestType & USB_DIR_IN) ||
+				!setup->wLength;
+	} else {
+		is_out = usb_endpoint_dir_out(&ep->desc);
+	}
+
+	/* Cache the direction for later use */
+	urb->transfer_flags = (urb->transfer_flags & ~URB_DIR_MASK) |
+			(is_out ? URB_DIR_OUT : URB_DIR_IN);
+
+	if (xfertype != USB_ENDPOINT_XFER_CONTROL &&
+			dev->state < USB_STATE_CONFIGURED)
 		return -ENODEV;
 
-	/* FIXME there should be a sharable lock protecting us against
-	 * config/altsetting changes and disconnects, kicking in here.
-	 * (here == before maxpacket, and eventually endpoint type,
-	 * checks get made.)
-	 */
-
-	max = usb_maxpacket(dev, pipe, is_out);
+	max = le16_to_cpu(ep->desc.wMaxPacketSize);
 	if (max <= 0) {
 		dev_dbg(&dev->dev,
 			"bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
-			usb_pipeendpoint(pipe), is_out ? "out" : "in",
+			usb_endpoint_num(&ep->desc), is_out ? "out" : "in",
 			__FUNCTION__, max);
 		return -EMSGSIZE;
 	}
@@ -323,7 +337,7 @@
 	 * but drivers only control those sizes for ISO.
 	 * while we're checking, initialize return status.
 	 */
-	if (temp == PIPE_ISOCHRONOUS) {
+	if (xfertype == USB_ENDPOINT_XFER_ISOC) {
 		int	n, len;
 
 		/* "high bandwidth" mode, 1-3 packets/uframe? */
@@ -358,20 +372,20 @@
 
 	/* enforce simple/standard policy */
 	allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP |
-			URB_NO_INTERRUPT);
-	switch (temp) {
-	case PIPE_BULK:
+			URB_NO_INTERRUPT | URB_DIR_MASK);
+	switch (xfertype) {
+	case USB_ENDPOINT_XFER_BULK:
 		if (is_out)
 			allowed |= URB_ZERO_PACKET;
 		/* FALLTHROUGH */
-	case PIPE_CONTROL:
+	case USB_ENDPOINT_XFER_CONTROL:
 		allowed |= URB_NO_FSBR;	/* only affects UHCI */
 		/* FALLTHROUGH */
 	default:			/* all non-iso endpoints */
 		if (!is_out)
 			allowed |= URB_SHORT_NOT_OK;
 		break;
-	case PIPE_ISOCHRONOUS:
+	case USB_ENDPOINT_XFER_ISOC:
 		allowed |= URB_ISO_ASAP;
 		break;
 	}
@@ -393,9 +407,9 @@
 	 * supports different values... this uses EHCI/UHCI defaults (and
 	 * EHCI can use smaller non-default values).
 	 */
-	switch (temp) {
-	case PIPE_ISOCHRONOUS:
-	case PIPE_INTERRUPT:
+	switch (xfertype) {
+	case USB_ENDPOINT_XFER_ISOC:
+	case USB_ENDPOINT_XFER_INT:
 		/* too small? */
 		if (urb->interval <= 0)
 			return -EINVAL;
@@ -405,29 +419,27 @@
 			// NOTE usb handles 2^15
 			if (urb->interval > (1024 * 8))
 				urb->interval = 1024 * 8;
-			temp = 1024 * 8;
+			max = 1024 * 8;
 			break;
 		case USB_SPEED_FULL:	/* units are frames/msec */
 		case USB_SPEED_LOW:
-			if (temp == PIPE_INTERRUPT) {
+			if (xfertype == USB_ENDPOINT_XFER_INT) {
 				if (urb->interval > 255)
 					return -EINVAL;
 				// NOTE ohci only handles up to 32
-				temp = 128;
+				max = 128;
 			} else {
 				if (urb->interval > 1024)
 					urb->interval = 1024;
 				// NOTE usb and ohci handle up to 2^15
-				temp = 1024;
+				max = 1024;
 			}
 			break;
 		default:
 			return -EINVAL;
 		}
-		/* power of two? */
-		while (temp > urb->interval)
-			temp >>= 1;
-		urb->interval = temp;
+		/* Round down to a power of 2, no more than max */
+		urb->interval = min(max, 1 << ilog2(urb->interval));
 	}
 
 	return usb_hcd_submit_urb(urb, mem_flags);
@@ -496,8 +508,10 @@
 {
 	if (!urb)
 		return -EINVAL;
-	if (!(urb->dev && urb->dev->bus))
+	if (!urb->dev)
 		return -ENODEV;
+	if (!urb->ep)
+		return -EIDRM;
 	return usb_hcd_unlink_urb(urb, -ECONNRESET);
 }
 
@@ -523,19 +537,21 @@
  */
 void usb_kill_urb(struct urb *urb)
 {
+	static DEFINE_MUTEX(reject_mutex);
+
 	might_sleep();
-	if (!(urb && urb->dev && urb->dev->bus))
+	if (!(urb && urb->dev && urb->ep))
 		return;
-	spin_lock_irq(&urb->lock);
+	mutex_lock(&reject_mutex);
 	++urb->reject;
-	spin_unlock_irq(&urb->lock);
+	mutex_unlock(&reject_mutex);
 
 	usb_hcd_unlink_urb(urb, -ENOENT);
 	wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);
 
-	spin_lock_irq(&urb->lock);
+	mutex_lock(&reject_mutex);
 	--urb->reject;
-	spin_unlock_irq(&urb->lock);
+	mutex_unlock(&reject_mutex);
 }
 
 /**
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 0fee5c6..c99938d 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -223,6 +223,15 @@
 
 #endif	/* CONFIG_PM */
 
+
+/* Returns 1 if @usb_bus is WUSB, 0 otherwise */
+static unsigned usb_bus_is_wusb(struct usb_bus *bus)
+{
+	struct usb_hcd *hcd = container_of(bus, struct usb_hcd, self);
+	return hcd->wireless;
+}
+
+
 /**
  * usb_alloc_dev - usb device constructor (usbcore-internal)
  * @parent: hub to which device is connected; null to allocate a root hub
@@ -239,6 +248,8 @@
 usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
 {
 	struct usb_device *dev;
+	struct usb_hcd *usb_hcd = container_of(bus, struct usb_hcd, self);
+	unsigned root_hub = 0;
 
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	if (!dev)
@@ -255,12 +266,14 @@
 	dev->dev.dma_mask = bus->controller->dma_mask;
 	set_dev_node(&dev->dev, dev_to_node(bus->controller));
 	dev->state = USB_STATE_ATTACHED;
+	atomic_set(&dev->urbnum, 0);
 
 	INIT_LIST_HEAD(&dev->ep0.urb_list);
 	dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
 	dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
 	/* ep0 maxpacket comes later, from device descriptor */
-	dev->ep_in[0] = dev->ep_out[0] = &dev->ep0;
+	usb_enable_endpoint(dev, &dev->ep0);
+	dev->can_submit = 1;
 
 	/* Save readable and stable topology id, distinguishing devices
 	 * by location for diagnostics, tools, driver model, etc.  The
@@ -275,6 +288,7 @@
 
 		dev->dev.parent = bus->controller;
 		sprintf(&dev->dev.bus_id[0], "usb%d", bus->busnum);
+		root_hub = 1;
 	} else {
 		/* match any labeling on the hubs; it's one-based */
 		if (parent->devpath[0] == '0')
@@ -301,6 +315,12 @@
 	INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work);
 	dev->autosuspend_delay = usb_autosuspend_delay * HZ;
 #endif
+	if (root_hub)	/* Root hub always ok [and always wired] */
+		dev->authorized = 1;
+	else {
+		dev->authorized = usb_hcd->authorized_default;
+		dev->wusb = usb_bus_is_wusb(bus)? 1 : 0;
+	}
 	return dev;
 }
 
@@ -748,7 +768,7 @@
 /**
  * usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint
  * @dev: device to which the scatterlist will be mapped
- * @pipe: endpoint defining the mapping direction
+ * @is_in: mapping transfer direction
  * @sg: the scatterlist to map
  * @nents: the number of entries in the scatterlist
  *
@@ -771,14 +791,13 @@
  *
  * Reverse the effect of this call with usb_buffer_unmap_sg().
  */
-int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
+int usb_buffer_map_sg(const struct usb_device *dev, int is_in,
 		      struct scatterlist *sg, int nents)
 {
 	struct usb_bus		*bus;
 	struct device		*controller;
 
 	if (!dev
-			|| usb_pipecontrol(pipe)
 			|| !(bus = dev->bus)
 			|| !(controller = bus->controller)
 			|| !controller->dma_mask)
@@ -786,7 +805,7 @@
 
 	// FIXME generic api broken like pci, can't report errors
 	return dma_map_sg(controller, sg, nents,
-			usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+			is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 
 /* XXX DISABLED, no users currently.  If you wish to re-enable this
@@ -799,14 +818,14 @@
 /**
  * usb_buffer_dmasync_sg - synchronize DMA and CPU view of scatterlist buffer(s)
  * @dev: device to which the scatterlist will be mapped
- * @pipe: endpoint defining the mapping direction
+ * @is_in: mapping transfer direction
  * @sg: the scatterlist to synchronize
  * @n_hw_ents: the positive return value from usb_buffer_map_sg
  *
  * Use this when you are re-using a scatterlist's data buffers for
  * another USB request.
  */
-void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe,
+void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in,
 			   struct scatterlist *sg, int n_hw_ents)
 {
 	struct usb_bus		*bus;
@@ -819,20 +838,20 @@
 		return;
 
 	dma_sync_sg(controller, sg, n_hw_ents,
-			usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+			is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 #endif
 
 /**
  * usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist
  * @dev: device to which the scatterlist will be mapped
- * @pipe: endpoint defining the mapping direction
+ * @is_in: mapping transfer direction
  * @sg: the scatterlist to unmap
  * @n_hw_ents: the positive return value from usb_buffer_map_sg
  *
  * Reverses the effect of usb_buffer_map_sg().
  */
-void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe,
+void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in,
 			 struct scatterlist *sg, int n_hw_ents)
 {
 	struct usb_bus		*bus;
@@ -845,7 +864,7 @@
 		return;
 
 	dma_unmap_sg(controller, sg, n_hw_ents,
-			usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+			is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 
 /* format to disable USB on kernel command line is: nousb */
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index ad5fa03..c52626c 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -8,17 +8,22 @@
 				struct usb_device *udev);
 extern void usb_remove_ep_files(struct usb_host_endpoint *endpoint);
 
+extern void usb_enable_endpoint(struct usb_device *dev,
+		struct usb_host_endpoint *ep);
 extern void usb_disable_endpoint (struct usb_device *dev, unsigned int epaddr);
 extern void usb_disable_interface (struct usb_device *dev,
 		struct usb_interface *intf);
 extern void usb_release_interface_cache(struct kref *ref);
 extern void usb_disable_device (struct usb_device *dev, int skip_ep0);
+extern int usb_deauthorize_device (struct usb_device *);
+extern int usb_authorize_device (struct usb_device *);
 extern void usb_detect_quirks(struct usb_device *udev);
 
 extern int usb_get_device_descriptor(struct usb_device *dev,
 		unsigned int size);
 extern char *usb_cache_string(struct usb_device *udev, int index);
 extern int usb_set_configuration(struct usb_device *dev, int configuration);
+extern int usb_choose_configuration(struct usb_device *udev);
 
 extern void usb_kick_khubd(struct usb_device *dev);
 extern int usb_match_device(struct usb_device *dev,
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 767aed5..f81d08d 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -67,6 +67,17 @@
 	   driver on a new board.   Enable these files by choosing "Y"
 	   here.  If in doubt, or to conserve kernel memory, say "N".
 
+config USB_GADGET_DEBUG_FS
+	boolean "Debugging information files in debugfs"
+	depends on USB_GADGET && DEBUG_FS
+	help
+	   Some of the drivers in the "gadget" framework can expose
+	   debugging information in files under /sys/kernel/debug/.
+	   The information in these files may help when you're
+	   troubleshooting or bringing up a driver on a new board.
+	   Enable these files by choosing "Y" here.  If in doubt, or
+	   to conserve kernel memory, say "N".
+
 config	USB_GADGET_SELECTED
 	boolean
 
@@ -103,6 +114,20 @@
 	default USB_GADGET
 	select USB_GADGET_SELECTED
 
+config USB_GADGET_ATMEL_USBA
+	boolean "Atmel USBA"
+	select USB_GADGET_DUALSPEED
+	depends on AVR32
+	help
+	  USBA is the integrated high-speed USB Device controller on
+	  the AT32AP700x processors from Atmel.
+
+config USB_ATMEL_USBA
+	tristate
+	depends on USB_GADGET_ATMEL_USBA
+	default USB_GADGET
+	select USB_GADGET_SELECTED
+
 config USB_GADGET_FSL_USB2
 	boolean "Freescale Highspeed USB DR Peripheral Controller"
 	depends on MPC834x || PPC_MPC831x
@@ -228,7 +253,6 @@
 	default USB_GADGET
 	select USB_GADGET_SELECTED
 
-
 config USB_GADGET_OMAP
 	boolean "OMAP USB Device Controller"
 	depends on ARCH_OMAP
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 1bc0f03..904e57b 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -14,6 +14,7 @@
 obj-$(CONFIG_USB_LH7A40X)	+= lh7a40x_udc.o
 obj-$(CONFIG_USB_S3C2410)	+= s3c2410_udc.o
 obj-$(CONFIG_USB_AT91)		+= at91_udc.o
+obj-$(CONFIG_USB_ATMEL_USBA)	+= atmel_usba_udc.o
 obj-$(CONFIG_USB_FSL_USB2)	+= fsl_usb2_udc.o
 obj-$(CONFIG_USB_M66592)	+= m66592-udc.o
 
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
index 714156c..1c80406 100644
--- a/drivers/usb/gadget/amd5536udc.c
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -69,7 +69,7 @@
 
 /* gadget stack */
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 /* udc specific */
 #include "amd5536udc.h"
@@ -3244,7 +3244,6 @@
 		retval = -ENOMEM;
 		goto finished;
 	}
-	memset(dev, 0, sizeof(struct udc));
 
 	/* pci setup */
 	if (pci_enable_device(pdev) < 0) {
@@ -3286,14 +3285,12 @@
 
 	pci_set_drvdata(pdev, dev);
 
-	/* chip revision */
-	dev->chiprev = 0;
+	/* chip revision for Hs AMD5536 */
+	dev->chiprev = pdev->revision;
 
 	pci_set_master(pdev);
 	pci_set_mwi(pdev);
 
-	/* chip rev for Hs AMD5536 */
-	pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) &dev->chiprev);
 	/* init dma pools */
 	if (use_dma) {
 		retval = init_dma_pools(dev);
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 63d7d65..a6adf7e 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -38,7 +38,7 @@
 #include <linux/proc_fs.h>
 #include <linux/clk.h>
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/byteorder.h>
 #include <asm/hardware.h>
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
new file mode 100644
index 0000000..4fb5ff4
--- /dev/null
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -0,0 +1,2077 @@
+/*
+ * Driver for the Atmel USBA high speed USB device controller
+ *
+ * Copyright (C) 2005-2007 Atmel 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/clk.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/delay.h>
+
+#include <asm/gpio.h>
+#include <asm/arch/board.h>
+
+#include "atmel_usba_udc.h"
+
+
+static struct usba_udc the_udc;
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+
+static int queue_dbg_open(struct inode *inode, struct file *file)
+{
+	struct usba_ep *ep = inode->i_private;
+	struct usba_request *req, *req_copy;
+	struct list_head *queue_data;
+
+	queue_data = kmalloc(sizeof(*queue_data), GFP_KERNEL);
+	if (!queue_data)
+		return -ENOMEM;
+	INIT_LIST_HEAD(queue_data);
+
+	spin_lock_irq(&ep->udc->lock);
+	list_for_each_entry(req, &ep->queue, queue) {
+		req_copy = kmalloc(sizeof(*req_copy), GFP_ATOMIC);
+		if (!req_copy)
+			goto fail;
+		memcpy(req_copy, req, sizeof(*req_copy));
+		list_add_tail(&req_copy->queue, queue_data);
+	}
+	spin_unlock_irq(&ep->udc->lock);
+
+	file->private_data = queue_data;
+	return 0;
+
+fail:
+	spin_unlock_irq(&ep->udc->lock);
+	list_for_each_entry_safe(req, req_copy, queue_data, queue) {
+		list_del(&req->queue);
+		kfree(req);
+	}
+	kfree(queue_data);
+	return -ENOMEM;
+}
+
+/*
+ * bbbbbbbb llllllll IZS sssss nnnn FDL\n\0
+ *
+ * b: buffer address
+ * l: buffer length
+ * I/i: interrupt/no interrupt
+ * Z/z: zero/no zero
+ * S/s: short ok/short not ok
+ * s: status
+ * n: nr_packets
+ * F/f: submitted/not submitted to FIFO
+ * D/d: using/not using DMA
+ * L/l: last transaction/not last transaction
+ */
+static ssize_t queue_dbg_read(struct file *file, char __user *buf,
+		size_t nbytes, loff_t *ppos)
+{
+	struct list_head *queue = file->private_data;
+	struct usba_request *req, *tmp_req;
+	size_t len, remaining, actual = 0;
+	char tmpbuf[38];
+
+	if (!access_ok(VERIFY_WRITE, buf, nbytes))
+		return -EFAULT;
+
+	mutex_lock(&file->f_dentry->d_inode->i_mutex);
+	list_for_each_entry_safe(req, tmp_req, queue, queue) {
+		len = snprintf(tmpbuf, sizeof(tmpbuf),
+				"%8p %08x %c%c%c %5d %c%c%c\n",
+				req->req.buf, req->req.length,
+				req->req.no_interrupt ? 'i' : 'I',
+				req->req.zero ? 'Z' : 'z',
+				req->req.short_not_ok ? 's' : 'S',
+				req->req.status,
+				req->submitted ? 'F' : 'f',
+				req->using_dma ? 'D' : 'd',
+				req->last_transaction ? 'L' : 'l');
+		len = min(len, sizeof(tmpbuf));
+		if (len > nbytes)
+			break;
+
+		list_del(&req->queue);
+		kfree(req);
+
+		remaining = __copy_to_user(buf, tmpbuf, len);
+		actual += len - remaining;
+		if (remaining)
+			break;
+
+		nbytes -= len;
+		buf += len;
+	}
+	mutex_unlock(&file->f_dentry->d_inode->i_mutex);
+
+	return actual;
+}
+
+static int queue_dbg_release(struct inode *inode, struct file *file)
+{
+	struct list_head *queue_data = file->private_data;
+	struct usba_request *req, *tmp_req;
+
+	list_for_each_entry_safe(req, tmp_req, queue_data, queue) {
+		list_del(&req->queue);
+		kfree(req);
+	}
+	kfree(queue_data);
+	return 0;
+}
+
+static int regs_dbg_open(struct inode *inode, struct file *file)
+{
+	struct usba_udc *udc;
+	unsigned int i;
+	u32 *data;
+	int ret = -ENOMEM;
+
+	mutex_lock(&inode->i_mutex);
+	udc = inode->i_private;
+	data = kmalloc(inode->i_size, GFP_KERNEL);
+	if (!data)
+		goto out;
+
+	spin_lock_irq(&udc->lock);
+	for (i = 0; i < inode->i_size / 4; i++)
+		data[i] = __raw_readl(udc->regs + i * 4);
+	spin_unlock_irq(&udc->lock);
+
+	file->private_data = data;
+	ret = 0;
+
+out:
+	mutex_unlock(&inode->i_mutex);
+
+	return ret;
+}
+
+static ssize_t regs_dbg_read(struct file *file, char __user *buf,
+		size_t nbytes, loff_t *ppos)
+{
+	struct inode *inode = file->f_dentry->d_inode;
+	int ret;
+
+	mutex_lock(&inode->i_mutex);
+	ret = simple_read_from_buffer(buf, nbytes, ppos,
+			file->private_data,
+			file->f_dentry->d_inode->i_size);
+	mutex_unlock(&inode->i_mutex);
+
+	return ret;
+}
+
+static int regs_dbg_release(struct inode *inode, struct file *file)
+{
+	kfree(file->private_data);
+	return 0;
+}
+
+const struct file_operations queue_dbg_fops = {
+	.owner		= THIS_MODULE,
+	.open		= queue_dbg_open,
+	.llseek		= no_llseek,
+	.read		= queue_dbg_read,
+	.release	= queue_dbg_release,
+};
+
+const struct file_operations regs_dbg_fops = {
+	.owner		= THIS_MODULE,
+	.open		= regs_dbg_open,
+	.llseek		= generic_file_llseek,
+	.read		= regs_dbg_read,
+	.release	= regs_dbg_release,
+};
+
+static void usba_ep_init_debugfs(struct usba_udc *udc,
+		struct usba_ep *ep)
+{
+	struct dentry *ep_root;
+
+	ep_root = debugfs_create_dir(ep->ep.name, udc->debugfs_root);
+	if (!ep_root)
+		goto err_root;
+	ep->debugfs_dir = ep_root;
+
+	ep->debugfs_queue = debugfs_create_file("queue", 0400, ep_root,
+						ep, &queue_dbg_fops);
+	if (!ep->debugfs_queue)
+		goto err_queue;
+
+	if (ep->can_dma) {
+		ep->debugfs_dma_status
+			= debugfs_create_u32("dma_status", 0400, ep_root,
+					&ep->last_dma_status);
+		if (!ep->debugfs_dma_status)
+			goto err_dma_status;
+	}
+	if (ep_is_control(ep)) {
+		ep->debugfs_state
+			= debugfs_create_u32("state", 0400, ep_root,
+					&ep->state);
+		if (!ep->debugfs_state)
+			goto err_state;
+	}
+
+	return;
+
+err_state:
+	if (ep->can_dma)
+		debugfs_remove(ep->debugfs_dma_status);
+err_dma_status:
+	debugfs_remove(ep->debugfs_queue);
+err_queue:
+	debugfs_remove(ep_root);
+err_root:
+	dev_err(&ep->udc->pdev->dev,
+		"failed to create debugfs directory for %s\n", ep->ep.name);
+}
+
+static void usba_ep_cleanup_debugfs(struct usba_ep *ep)
+{
+	debugfs_remove(ep->debugfs_queue);
+	debugfs_remove(ep->debugfs_dma_status);
+	debugfs_remove(ep->debugfs_state);
+	debugfs_remove(ep->debugfs_dir);
+	ep->debugfs_dma_status = NULL;
+	ep->debugfs_dir = NULL;
+}
+
+static void usba_init_debugfs(struct usba_udc *udc)
+{
+	struct dentry *root, *regs;
+	struct resource *regs_resource;
+
+	root = debugfs_create_dir(udc->gadget.name, NULL);
+	if (IS_ERR(root) || !root)
+		goto err_root;
+	udc->debugfs_root = root;
+
+	regs = debugfs_create_file("regs", 0400, root, udc, &regs_dbg_fops);
+	if (!regs)
+		goto err_regs;
+
+	regs_resource = platform_get_resource(udc->pdev, IORESOURCE_MEM,
+				CTRL_IOMEM_ID);
+	regs->d_inode->i_size = regs_resource->end - regs_resource->start + 1;
+	udc->debugfs_regs = regs;
+
+	usba_ep_init_debugfs(udc, to_usba_ep(udc->gadget.ep0));
+
+	return;
+
+err_regs:
+	debugfs_remove(root);
+err_root:
+	udc->debugfs_root = NULL;
+	dev_err(&udc->pdev->dev, "debugfs is not available\n");
+}
+
+static void usba_cleanup_debugfs(struct usba_udc *udc)
+{
+	usba_ep_cleanup_debugfs(to_usba_ep(udc->gadget.ep0));
+	debugfs_remove(udc->debugfs_regs);
+	debugfs_remove(udc->debugfs_root);
+	udc->debugfs_regs = NULL;
+	udc->debugfs_root = NULL;
+}
+#else
+static inline void usba_ep_init_debugfs(struct usba_udc *udc,
+					 struct usba_ep *ep)
+{
+
+}
+
+static inline void usba_ep_cleanup_debugfs(struct usba_ep *ep)
+{
+
+}
+
+static inline void usba_init_debugfs(struct usba_udc *udc)
+{
+
+}
+
+static inline void usba_cleanup_debugfs(struct usba_udc *udc)
+{
+
+}
+#endif
+
+static int vbus_is_present(struct usba_udc *udc)
+{
+	if (udc->vbus_pin != -1)
+		return gpio_get_value(udc->vbus_pin);
+
+	/* No Vbus detection: Assume always present */
+	return 1;
+}
+
+static void copy_to_fifo(void __iomem *fifo, const void *buf, int len)
+{
+	unsigned long tmp;
+
+	DBG(DBG_FIFO, "copy to FIFO (len %d):\n", len);
+	for (; len > 0; len -= 4, buf += 4, fifo += 4) {
+		tmp = *(unsigned long *)buf;
+		if (len >= 4) {
+			DBG(DBG_FIFO, "  -> %08lx\n", tmp);
+			__raw_writel(tmp, fifo);
+		} else {
+			do {
+				DBG(DBG_FIFO, "  -> %02lx\n", tmp >> 24);
+				__raw_writeb(tmp >> 24, fifo);
+				fifo++;
+				tmp <<= 8;
+			} while (--len);
+			break;
+		}
+	}
+}
+
+static void copy_from_fifo(void *buf, void __iomem *fifo, int len)
+{
+	union {
+		unsigned long *w;
+		unsigned char *b;
+	} p;
+	unsigned long tmp;
+
+	DBG(DBG_FIFO, "copy from FIFO (len %d):\n", len);
+	for (p.w = buf; len > 0; len -= 4, p.w++, fifo += 4) {
+		if (len >= 4) {
+			tmp = __raw_readl(fifo);
+			*p.w = tmp;
+			DBG(DBG_FIFO, "  -> %08lx\n", tmp);
+		} else {
+			do {
+				tmp = __raw_readb(fifo);
+				*p.b = tmp;
+				DBG(DBG_FIFO, " -> %02lx\n", tmp);
+				fifo++, p.b++;
+			} while (--len);
+		}
+	}
+}
+
+static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req)
+{
+	unsigned int transaction_len;
+
+	transaction_len = req->req.length - req->req.actual;
+	req->last_transaction = 1;
+	if (transaction_len > ep->ep.maxpacket) {
+		transaction_len = ep->ep.maxpacket;
+		req->last_transaction = 0;
+	} else if (transaction_len == ep->ep.maxpacket && req->req.zero)
+		req->last_transaction = 0;
+
+	DBG(DBG_QUEUE, "%s: submit_transaction, req %p (length %d)%s\n",
+		ep->ep.name, req, transaction_len,
+		req->last_transaction ? ", done" : "");
+
+	copy_to_fifo(ep->fifo, req->req.buf + req->req.actual, transaction_len);
+	usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+	req->req.actual += transaction_len;
+}
+
+static void submit_request(struct usba_ep *ep, struct usba_request *req)
+{
+	DBG(DBG_QUEUE, "%s: submit_request: req %p (length %d)\n",
+		ep->ep.name, req, req->req.length);
+
+	req->req.actual = 0;
+	req->submitted = 1;
+
+	if (req->using_dma) {
+		if (req->req.length == 0) {
+			usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
+			return;
+		}
+
+		if (req->req.zero)
+			usba_ep_writel(ep, CTL_ENB, USBA_SHORT_PACKET);
+		else
+			usba_ep_writel(ep, CTL_DIS, USBA_SHORT_PACKET);
+
+		usba_dma_writel(ep, ADDRESS, req->req.dma);
+		usba_dma_writel(ep, CONTROL, req->ctrl);
+	} else {
+		next_fifo_transaction(ep, req);
+		if (req->last_transaction) {
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
+			usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
+		} else {
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+			usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
+		}
+	}
+}
+
+static void submit_next_request(struct usba_ep *ep)
+{
+	struct usba_request *req;
+
+	if (list_empty(&ep->queue)) {
+		usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY | USBA_RX_BK_RDY);
+		return;
+	}
+
+	req = list_entry(ep->queue.next, struct usba_request, queue);
+	if (!req->submitted)
+		submit_request(ep, req);
+}
+
+static void send_status(struct usba_udc *udc, struct usba_ep *ep)
+{
+	ep->state = STATUS_STAGE_IN;
+	usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+	usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
+}
+
+static void receive_data(struct usba_ep *ep)
+{
+	struct usba_udc *udc = ep->udc;
+	struct usba_request *req;
+	unsigned long status;
+	unsigned int bytecount, nr_busy;
+	int is_complete = 0;
+
+	status = usba_ep_readl(ep, STA);
+	nr_busy = USBA_BFEXT(BUSY_BANKS, status);
+
+	DBG(DBG_QUEUE, "receive data: nr_busy=%u\n", nr_busy);
+
+	while (nr_busy > 0) {
+		if (list_empty(&ep->queue)) {
+			usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+			break;
+		}
+		req = list_entry(ep->queue.next,
+				 struct usba_request, queue);
+
+		bytecount = USBA_BFEXT(BYTE_COUNT, status);
+
+		if (status & (1 << 31))
+			is_complete = 1;
+		if (req->req.actual + bytecount >= req->req.length) {
+			is_complete = 1;
+			bytecount = req->req.length - req->req.actual;
+		}
+
+		copy_from_fifo(req->req.buf + req->req.actual,
+				ep->fifo, bytecount);
+		req->req.actual += bytecount;
+
+		usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+
+		if (is_complete) {
+			DBG(DBG_QUEUE, "%s: request done\n", ep->ep.name);
+			req->req.status = 0;
+			list_del_init(&req->queue);
+			usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+			spin_unlock(&udc->lock);
+			req->req.complete(&ep->ep, &req->req);
+			spin_lock(&udc->lock);
+		}
+
+		status = usba_ep_readl(ep, STA);
+		nr_busy = USBA_BFEXT(BUSY_BANKS, status);
+
+		if (is_complete && ep_is_control(ep)) {
+			send_status(udc, ep);
+			break;
+		}
+	}
+}
+
+static void
+request_complete(struct usba_ep *ep, struct usba_request *req, int status)
+{
+	struct usba_udc *udc = ep->udc;
+
+	WARN_ON(!list_empty(&req->queue));
+
+	if (req->req.status == -EINPROGRESS)
+		req->req.status = status;
+
+	if (req->mapped) {
+		dma_unmap_single(
+			&udc->pdev->dev, req->req.dma, req->req.length,
+			ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+		req->req.dma = DMA_ADDR_INVALID;
+		req->mapped = 0;
+	}
+
+	DBG(DBG_GADGET | DBG_REQ,
+		"%s: req %p complete: status %d, actual %u\n",
+		ep->ep.name, req, req->req.status, req->req.actual);
+
+	spin_unlock(&udc->lock);
+	req->req.complete(&ep->ep, &req->req);
+	spin_lock(&udc->lock);
+}
+
+static void
+request_complete_list(struct usba_ep *ep, struct list_head *list, int status)
+{
+	struct usba_request *req, *tmp_req;
+
+	list_for_each_entry_safe(req, tmp_req, list, queue) {
+		list_del_init(&req->queue);
+		request_complete(ep, req, status);
+	}
+}
+
+static int
+usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
+{
+	struct usba_ep *ep = to_usba_ep(_ep);
+	struct usba_udc *udc = ep->udc;
+	unsigned long flags, ept_cfg, maxpacket;
+	unsigned int nr_trans;
+
+	DBG(DBG_GADGET, "%s: ep_enable: desc=%p\n", ep->ep.name, desc);
+
+	maxpacket = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff;
+
+	if (((desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) != ep->index)
+			|| ep->index == 0
+			|| desc->bDescriptorType != USB_DT_ENDPOINT
+			|| maxpacket == 0
+			|| maxpacket > ep->fifo_size) {
+		DBG(DBG_ERR, "ep_enable: Invalid argument");
+		return -EINVAL;
+	}
+
+	ep->is_isoc = 0;
+	ep->is_in = 0;
+
+	if (maxpacket <= 8)
+		ept_cfg = USBA_BF(EPT_SIZE, USBA_EPT_SIZE_8);
+	else
+		/* LSB is bit 1, not 0 */
+		ept_cfg = USBA_BF(EPT_SIZE, fls(maxpacket - 1) - 3);
+
+	DBG(DBG_HW, "%s: EPT_SIZE = %lu (maxpacket = %lu)\n",
+			ep->ep.name, ept_cfg, maxpacket);
+
+	if ((desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
+		ep->is_in = 1;
+		ept_cfg |= USBA_EPT_DIR_IN;
+	}
+
+	switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL);
+		ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE);
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		if (!ep->can_isoc) {
+			DBG(DBG_ERR, "ep_enable: %s is not isoc capable\n",
+					ep->ep.name);
+			return -EINVAL;
+		}
+
+		/*
+		 * Bits 11:12 specify number of _additional_
+		 * transactions per microframe.
+		 */
+		nr_trans = ((le16_to_cpu(desc->wMaxPacketSize) >> 11) & 3) + 1;
+		if (nr_trans > 3)
+			return -EINVAL;
+
+		ep->is_isoc = 1;
+		ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_ISO);
+
+		/*
+		 * Do triple-buffering on high-bandwidth iso endpoints.
+		 */
+		if (nr_trans > 1 && ep->nr_banks == 3)
+			ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_TRIPLE);
+		else
+			ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE);
+		ept_cfg |= USBA_BF(NB_TRANS, nr_trans);
+		break;
+	case USB_ENDPOINT_XFER_BULK:
+		ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK);
+		ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE);
+		break;
+	case USB_ENDPOINT_XFER_INT:
+		ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_INT);
+		ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE);
+		break;
+	}
+
+	spin_lock_irqsave(&ep->udc->lock, flags);
+
+	if (ep->desc) {
+		spin_unlock_irqrestore(&ep->udc->lock, flags);
+		DBG(DBG_ERR, "ep%d already enabled\n", ep->index);
+		return -EBUSY;
+	}
+
+	ep->desc = desc;
+	ep->ep.maxpacket = maxpacket;
+
+	usba_ep_writel(ep, CFG, ept_cfg);
+	usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE);
+
+	if (ep->can_dma) {
+		u32 ctrl;
+
+		usba_writel(udc, INT_ENB,
+				(usba_readl(udc, INT_ENB)
+					| USBA_BF(EPT_INT, 1 << ep->index)
+					| USBA_BF(DMA_INT, 1 << ep->index)));
+		ctrl = USBA_AUTO_VALID | USBA_INTDIS_DMA;
+		usba_ep_writel(ep, CTL_ENB, ctrl);
+	} else {
+		usba_writel(udc, INT_ENB,
+				(usba_readl(udc, INT_ENB)
+					| USBA_BF(EPT_INT, 1 << ep->index)));
+	}
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	DBG(DBG_HW, "EPT_CFG%d after init: %#08lx\n", ep->index,
+			(unsigned long)usba_ep_readl(ep, CFG));
+	DBG(DBG_HW, "INT_ENB after init: %#08lx\n",
+			(unsigned long)usba_readl(udc, INT_ENB));
+
+	return 0;
+}
+
+static int usba_ep_disable(struct usb_ep *_ep)
+{
+	struct usba_ep *ep = to_usba_ep(_ep);
+	struct usba_udc *udc = ep->udc;
+	LIST_HEAD(req_list);
+	unsigned long flags;
+
+	DBG(DBG_GADGET, "ep_disable: %s\n", ep->ep.name);
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	if (!ep->desc) {
+		spin_unlock_irqrestore(&udc->lock, flags);
+		DBG(DBG_ERR, "ep_disable: %s not enabled\n", ep->ep.name);
+		return -EINVAL;
+	}
+	ep->desc = NULL;
+
+	list_splice_init(&ep->queue, &req_list);
+	if (ep->can_dma) {
+		usba_dma_writel(ep, CONTROL, 0);
+		usba_dma_writel(ep, ADDRESS, 0);
+		usba_dma_readl(ep, STATUS);
+	}
+	usba_ep_writel(ep, CTL_DIS, USBA_EPT_ENABLE);
+	usba_writel(udc, INT_ENB,
+			usba_readl(udc, INT_ENB)
+			& ~USBA_BF(EPT_INT, 1 << ep->index));
+
+	request_complete_list(ep, &req_list, -ESHUTDOWN);
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return 0;
+}
+
+static struct usb_request *
+usba_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
+{
+	struct usba_request *req;
+
+	DBG(DBG_GADGET, "ep_alloc_request: %p, 0x%x\n", _ep, gfp_flags);
+
+	req = kzalloc(sizeof(*req), gfp_flags);
+	if (!req)
+		return NULL;
+
+	INIT_LIST_HEAD(&req->queue);
+	req->req.dma = DMA_ADDR_INVALID;
+
+	return &req->req;
+}
+
+static void
+usba_ep_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct usba_request *req = to_usba_req(_req);
+
+	DBG(DBG_GADGET, "ep_free_request: %p, %p\n", _ep, _req);
+
+	kfree(req);
+}
+
+static int queue_dma(struct usba_udc *udc, struct usba_ep *ep,
+		struct usba_request *req, gfp_t gfp_flags)
+{
+	unsigned long flags;
+	int ret;
+
+	DBG(DBG_DMA, "%s: req l/%u d/%08x %c%c%c\n",
+		ep->ep.name, req->req.length, req->req.dma,
+		req->req.zero ? 'Z' : 'z',
+		req->req.short_not_ok ? 'S' : 's',
+		req->req.no_interrupt ? 'I' : 'i');
+
+	if (req->req.length > 0x10000) {
+		/* Lengths from 0 to 65536 (inclusive) are supported */
+		DBG(DBG_ERR, "invalid request length %u\n", req->req.length);
+		return -EINVAL;
+	}
+
+	req->using_dma = 1;
+
+	if (req->req.dma == DMA_ADDR_INVALID) {
+		req->req.dma = dma_map_single(
+			&udc->pdev->dev, req->req.buf, req->req.length,
+			ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+		req->mapped = 1;
+	} else {
+		dma_sync_single_for_device(
+			&udc->pdev->dev, req->req.dma, req->req.length,
+			ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+		req->mapped = 0;
+	}
+
+	req->ctrl = USBA_BF(DMA_BUF_LEN, req->req.length)
+			| USBA_DMA_CH_EN | USBA_DMA_END_BUF_IE
+			| USBA_DMA_END_TR_EN | USBA_DMA_END_TR_IE;
+
+	if (ep->is_in)
+		req->ctrl |= USBA_DMA_END_BUF_EN;
+
+	/*
+	 * Add this request to the queue and submit for DMA if
+	 * possible. Check if we're still alive first -- we may have
+	 * received a reset since last time we checked.
+	 */
+	ret = -ESHUTDOWN;
+	spin_lock_irqsave(&udc->lock, flags);
+	if (ep->desc) {
+		if (list_empty(&ep->queue))
+			submit_request(ep, req);
+
+		list_add_tail(&req->queue, &ep->queue);
+		ret = 0;
+	}
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return ret;
+}
+
+static int
+usba_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+{
+	struct usba_request *req = to_usba_req(_req);
+	struct usba_ep *ep = to_usba_ep(_ep);
+	struct usba_udc *udc = ep->udc;
+	unsigned long flags;
+	int ret;
+
+	DBG(DBG_GADGET | DBG_QUEUE | DBG_REQ, "%s: queue req %p, len %u\n",
+			ep->ep.name, req, _req->length);
+
+	if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN || !ep->desc)
+		return -ESHUTDOWN;
+
+	req->submitted = 0;
+	req->using_dma = 0;
+	req->last_transaction = 0;
+
+	_req->status = -EINPROGRESS;
+	_req->actual = 0;
+
+	if (ep->can_dma)
+		return queue_dma(udc, ep, req, gfp_flags);
+
+	/* May have received a reset since last time we checked */
+	ret = -ESHUTDOWN;
+	spin_lock_irqsave(&udc->lock, flags);
+	if (ep->desc) {
+		list_add_tail(&req->queue, &ep->queue);
+
+		if (ep->is_in || (ep_is_control(ep)
+				&& (ep->state == DATA_STAGE_IN
+					|| ep->state == STATUS_STAGE_IN)))
+			usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
+		else
+			usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY);
+		ret = 0;
+	}
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return ret;
+}
+
+static void
+usba_update_req(struct usba_ep *ep, struct usba_request *req, u32 status)
+{
+	req->req.actual = req->req.length - USBA_BFEXT(DMA_BUF_LEN, status);
+}
+
+static int stop_dma(struct usba_ep *ep, u32 *pstatus)
+{
+	unsigned int timeout;
+	u32 status;
+
+	/*
+	 * Stop the DMA controller. When writing both CH_EN
+	 * and LINK to 0, the other bits are not affected.
+	 */
+	usba_dma_writel(ep, CONTROL, 0);
+
+	/* Wait for the FIFO to empty */
+	for (timeout = 40; timeout; --timeout) {
+		status = usba_dma_readl(ep, STATUS);
+		if (!(status & USBA_DMA_CH_EN))
+			break;
+		udelay(1);
+	}
+
+	if (pstatus)
+		*pstatus = status;
+
+	if (timeout == 0) {
+		dev_err(&ep->udc->pdev->dev,
+			"%s: timed out waiting for DMA FIFO to empty\n",
+			ep->ep.name);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int usba_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct usba_ep *ep = to_usba_ep(_ep);
+	struct usba_udc *udc = ep->udc;
+	struct usba_request *req = to_usba_req(_req);
+	unsigned long flags;
+	u32 status;
+
+	DBG(DBG_GADGET | DBG_QUEUE, "ep_dequeue: %s, req %p\n",
+			ep->ep.name, req);
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	if (req->using_dma) {
+		/*
+		 * If this request is currently being transferred,
+		 * stop the DMA controller and reset the FIFO.
+		 */
+		if (ep->queue.next == &req->queue) {
+			status = usba_dma_readl(ep, STATUS);
+			if (status & USBA_DMA_CH_EN)
+				stop_dma(ep, &status);
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+			ep->last_dma_status = status;
+#endif
+
+			usba_writel(udc, EPT_RST, 1 << ep->index);
+
+			usba_update_req(ep, req, status);
+		}
+	}
+
+	/*
+	 * Errors should stop the queue from advancing until the
+	 * completion function returns.
+	 */
+	list_del_init(&req->queue);
+
+	request_complete(ep, req, -ECONNRESET);
+
+	/* Process the next request if any */
+	submit_next_request(ep);
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return 0;
+}
+
+static int usba_ep_set_halt(struct usb_ep *_ep, int value)
+{
+	struct usba_ep *ep = to_usba_ep(_ep);
+	struct usba_udc *udc = ep->udc;
+	unsigned long flags;
+	int ret = 0;
+
+	DBG(DBG_GADGET, "endpoint %s: %s HALT\n", ep->ep.name,
+			value ? "set" : "clear");
+
+	if (!ep->desc) {
+		DBG(DBG_ERR, "Attempted to halt uninitialized ep %s\n",
+				ep->ep.name);
+		return -ENODEV;
+	}
+	if (ep->is_isoc) {
+		DBG(DBG_ERR, "Attempted to halt isochronous ep %s\n",
+				ep->ep.name);
+		return -ENOTTY;
+	}
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	/*
+	 * We can't halt IN endpoints while there are still data to be
+	 * transferred
+	 */
+	if (!list_empty(&ep->queue)
+			|| ((value && ep->is_in && (usba_ep_readl(ep, STA)
+					& USBA_BF(BUSY_BANKS, -1L))))) {
+		ret = -EAGAIN;
+	} else {
+		if (value)
+			usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL);
+		else
+			usba_ep_writel(ep, CLR_STA,
+					USBA_FORCE_STALL | USBA_TOGGLE_CLR);
+		usba_ep_readl(ep, STA);
+	}
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return ret;
+}
+
+static int usba_ep_fifo_status(struct usb_ep *_ep)
+{
+	struct usba_ep *ep = to_usba_ep(_ep);
+
+	return USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA));
+}
+
+static void usba_ep_fifo_flush(struct usb_ep *_ep)
+{
+	struct usba_ep *ep = to_usba_ep(_ep);
+	struct usba_udc *udc = ep->udc;
+
+	usba_writel(udc, EPT_RST, 1 << ep->index);
+}
+
+static const struct usb_ep_ops usba_ep_ops = {
+	.enable		= usba_ep_enable,
+	.disable	= usba_ep_disable,
+	.alloc_request	= usba_ep_alloc_request,
+	.free_request	= usba_ep_free_request,
+	.queue		= usba_ep_queue,
+	.dequeue	= usba_ep_dequeue,
+	.set_halt	= usba_ep_set_halt,
+	.fifo_status	= usba_ep_fifo_status,
+	.fifo_flush	= usba_ep_fifo_flush,
+};
+
+static int usba_udc_get_frame(struct usb_gadget *gadget)
+{
+	struct usba_udc *udc = to_usba_udc(gadget);
+
+	return USBA_BFEXT(FRAME_NUMBER, usba_readl(udc, FNUM));
+}
+
+static int usba_udc_wakeup(struct usb_gadget *gadget)
+{
+	struct usba_udc *udc = to_usba_udc(gadget);
+	unsigned long flags;
+	u32 ctrl;
+	int ret = -EINVAL;
+
+	spin_lock_irqsave(&udc->lock, flags);
+	if (udc->devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) {
+		ctrl = usba_readl(udc, CTRL);
+		usba_writel(udc, CTRL, ctrl | USBA_REMOTE_WAKE_UP);
+		ret = 0;
+	}
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return ret;
+}
+
+static int
+usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)
+{
+	struct usba_udc *udc = to_usba_udc(gadget);
+	unsigned long flags;
+
+	spin_lock_irqsave(&udc->lock, flags);
+	if (is_selfpowered)
+		udc->devstatus |= 1 << USB_DEVICE_SELF_POWERED;
+	else
+		udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return 0;
+}
+
+static const struct usb_gadget_ops usba_udc_ops = {
+	.get_frame		= usba_udc_get_frame,
+	.wakeup			= usba_udc_wakeup,
+	.set_selfpowered	= usba_udc_set_selfpowered,
+};
+
+#define EP(nam, idx, maxpkt, maxbk, dma, isoc)			\
+{								\
+	.ep	= {						\
+		.ops		= &usba_ep_ops,			\
+		.name		= nam,				\
+		.maxpacket	= maxpkt,			\
+	},							\
+	.udc		= &the_udc,				\
+	.queue		= LIST_HEAD_INIT(usba_ep[idx].queue),	\
+	.fifo_size	= maxpkt,				\
+	.nr_banks	= maxbk,				\
+	.index		= idx,					\
+	.can_dma	= dma,					\
+	.can_isoc	= isoc,					\
+}
+
+static struct usba_ep usba_ep[] = {
+	EP("ep0", 0, 64, 1, 0, 0),
+	EP("ep1in-bulk", 1, 512, 2, 1, 1),
+	EP("ep2out-bulk", 2, 512, 2, 1, 1),
+	EP("ep3in-int", 3, 64, 3, 1, 0),
+	EP("ep4out-int", 4, 64, 3, 1, 0),
+	EP("ep5in-iso", 5, 1024, 3, 1, 1),
+	EP("ep6out-iso", 6, 1024, 3, 1, 1),
+};
+#undef EP
+
+static struct usb_endpoint_descriptor usba_ep0_desc = {
+	.bLength = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType = USB_DT_ENDPOINT,
+	.bEndpointAddress = 0,
+	.bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+	.wMaxPacketSize = __constant_cpu_to_le16(64),
+	/* FIXME: I have no idea what to put here */
+	.bInterval = 1,
+};
+
+static void nop_release(struct device *dev)
+{
+
+}
+
+static struct usba_udc the_udc = {
+	.gadget	= {
+		.ops		= &usba_udc_ops,
+		.ep0		= &usba_ep[0].ep,
+		.ep_list	= LIST_HEAD_INIT(the_udc.gadget.ep_list),
+		.is_dualspeed	= 1,
+		.name		= "atmel_usba_udc",
+		.dev	= {
+			.bus_id		= "gadget",
+			.release	= nop_release,
+		},
+	},
+
+	.lock	= SPIN_LOCK_UNLOCKED,
+};
+
+/*
+ * Called with interrupts disabled and udc->lock held.
+ */
+static void reset_all_endpoints(struct usba_udc *udc)
+{
+	struct usba_ep *ep;
+	struct usba_request *req, *tmp_req;
+
+	usba_writel(udc, EPT_RST, ~0UL);
+
+	ep = to_usba_ep(udc->gadget.ep0);
+	list_for_each_entry_safe(req, tmp_req, &ep->queue, queue) {
+		list_del_init(&req->queue);
+		request_complete(ep, req, -ECONNRESET);
+	}
+
+	list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
+		if (ep->desc) {
+			spin_unlock(&udc->lock);
+			usba_ep_disable(&ep->ep);
+			spin_lock(&udc->lock);
+		}
+	}
+}
+
+static struct usba_ep *get_ep_by_addr(struct usba_udc *udc, u16 wIndex)
+{
+	struct usba_ep *ep;
+
+	if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0)
+		return to_usba_ep(udc->gadget.ep0);
+
+	list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) {
+		u8 bEndpointAddress;
+
+		if (!ep->desc)
+			continue;
+		bEndpointAddress = ep->desc->bEndpointAddress;
+		if ((wIndex ^ bEndpointAddress) & USB_DIR_IN)
+			continue;
+		if ((bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)
+				== (wIndex & USB_ENDPOINT_NUMBER_MASK))
+			return ep;
+	}
+
+	return NULL;
+}
+
+/* Called with interrupts disabled and udc->lock held */
+static inline void set_protocol_stall(struct usba_udc *udc, struct usba_ep *ep)
+{
+	usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL);
+	ep->state = WAIT_FOR_SETUP;
+}
+
+static inline int is_stalled(struct usba_udc *udc, struct usba_ep *ep)
+{
+	if (usba_ep_readl(ep, STA) & USBA_FORCE_STALL)
+		return 1;
+	return 0;
+}
+
+static inline void set_address(struct usba_udc *udc, unsigned int addr)
+{
+	u32 regval;
+
+	DBG(DBG_BUS, "setting address %u...\n", addr);
+	regval = usba_readl(udc, CTRL);
+	regval = USBA_BFINS(DEV_ADDR, addr, regval);
+	usba_writel(udc, CTRL, regval);
+}
+
+static int do_test_mode(struct usba_udc *udc)
+{
+	static const char test_packet_buffer[] = {
+		/* JKJKJKJK * 9 */
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		/* JJKKJJKK * 8 */
+		0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+		/* JJKKJJKK * 8 */
+		0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
+		/* JJJJJJJKKKKKKK * 8 */
+		0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+		/* JJJJJJJK * 8 */
+		0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD,
+		/* {JKKKKKKK * 10}, JK */
+		0xFC, 0x7E, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0x7E
+	};
+	struct usba_ep *ep;
+	struct device *dev = &udc->pdev->dev;
+	int test_mode;
+
+	test_mode = udc->test_mode;
+
+	/* Start from a clean slate */
+	reset_all_endpoints(udc);
+
+	switch (test_mode) {
+	case 0x0100:
+		/* Test_J */
+		usba_writel(udc, TST, USBA_TST_J_MODE);
+		dev_info(dev, "Entering Test_J mode...\n");
+		break;
+	case 0x0200:
+		/* Test_K */
+		usba_writel(udc, TST, USBA_TST_K_MODE);
+		dev_info(dev, "Entering Test_K mode...\n");
+		break;
+	case 0x0300:
+		/*
+		 * Test_SE0_NAK: Force high-speed mode and set up ep0
+		 * for Bulk IN transfers
+		 */
+		ep = &usba_ep[0];
+		usba_writel(udc, TST,
+				USBA_BF(SPEED_CFG, USBA_SPEED_CFG_FORCE_HIGH));
+		usba_ep_writel(ep, CFG,
+				USBA_BF(EPT_SIZE, USBA_EPT_SIZE_64)
+				| USBA_EPT_DIR_IN
+				| USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK)
+				| USBA_BF(BK_NUMBER, 1));
+		if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) {
+			set_protocol_stall(udc, ep);
+			dev_err(dev, "Test_SE0_NAK: ep0 not mapped\n");
+		} else {
+			usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE);
+			dev_info(dev, "Entering Test_SE0_NAK mode...\n");
+		}
+		break;
+	case 0x0400:
+		/* Test_Packet */
+		ep = &usba_ep[0];
+		usba_ep_writel(ep, CFG,
+				USBA_BF(EPT_SIZE, USBA_EPT_SIZE_64)
+				| USBA_EPT_DIR_IN
+				| USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK)
+				| USBA_BF(BK_NUMBER, 1));
+		if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) {
+			set_protocol_stall(udc, ep);
+			dev_err(dev, "Test_Packet: ep0 not mapped\n");
+		} else {
+			usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE);
+			usba_writel(udc, TST, USBA_TST_PKT_MODE);
+			copy_to_fifo(ep->fifo, test_packet_buffer,
+					sizeof(test_packet_buffer));
+			usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+			dev_info(dev, "Entering Test_Packet mode...\n");
+		}
+		break;
+	default:
+		dev_err(dev, "Invalid test mode: 0x%04x\n", test_mode);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Avoid overly long expressions */
+static inline bool feature_is_dev_remote_wakeup(struct usb_ctrlrequest *crq)
+{
+	if (crq->wValue == __constant_cpu_to_le16(USB_DEVICE_REMOTE_WAKEUP))
+		return true;
+	return false;
+}
+
+static inline bool feature_is_dev_test_mode(struct usb_ctrlrequest *crq)
+{
+	if (crq->wValue == __constant_cpu_to_le16(USB_DEVICE_TEST_MODE))
+		return true;
+	return false;
+}
+
+static inline bool feature_is_ep_halt(struct usb_ctrlrequest *crq)
+{
+	if (crq->wValue == __constant_cpu_to_le16(USB_ENDPOINT_HALT))
+		return true;
+	return false;
+}
+
+static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep,
+		struct usb_ctrlrequest *crq)
+{
+	int retval = 0;;
+
+	switch (crq->bRequest) {
+	case USB_REQ_GET_STATUS: {
+		u16 status;
+
+		if (crq->bRequestType == (USB_DIR_IN | USB_RECIP_DEVICE)) {
+			status = cpu_to_le16(udc->devstatus);
+		} else if (crq->bRequestType
+				== (USB_DIR_IN | USB_RECIP_INTERFACE)) {
+			status = __constant_cpu_to_le16(0);
+		} else if (crq->bRequestType
+				== (USB_DIR_IN | USB_RECIP_ENDPOINT)) {
+			struct usba_ep *target;
+
+			target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex));
+			if (!target)
+				goto stall;
+
+			status = 0;
+			if (is_stalled(udc, target))
+				status |= __constant_cpu_to_le16(1);
+		} else
+			goto delegate;
+
+		/* Write directly to the FIFO. No queueing is done. */
+		if (crq->wLength != __constant_cpu_to_le16(sizeof(status)))
+			goto stall;
+		ep->state = DATA_STAGE_IN;
+		__raw_writew(status, ep->fifo);
+		usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+		break;
+	}
+
+	case USB_REQ_CLEAR_FEATURE: {
+		if (crq->bRequestType == USB_RECIP_DEVICE) {
+			if (feature_is_dev_remote_wakeup(crq))
+				udc->devstatus
+					&= ~(1 << USB_DEVICE_REMOTE_WAKEUP);
+			else
+				/* Can't CLEAR_FEATURE TEST_MODE */
+				goto stall;
+		} else if (crq->bRequestType == USB_RECIP_ENDPOINT) {
+			struct usba_ep *target;
+
+			if (crq->wLength != __constant_cpu_to_le16(0)
+					|| !feature_is_ep_halt(crq))
+				goto stall;
+			target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex));
+			if (!target)
+				goto stall;
+
+			usba_ep_writel(target, CLR_STA, USBA_FORCE_STALL);
+			if (target->index != 0)
+				usba_ep_writel(target, CLR_STA,
+						USBA_TOGGLE_CLR);
+		} else {
+			goto delegate;
+		}
+
+		send_status(udc, ep);
+		break;
+	}
+
+	case USB_REQ_SET_FEATURE: {
+		if (crq->bRequestType == USB_RECIP_DEVICE) {
+			if (feature_is_dev_test_mode(crq)) {
+				send_status(udc, ep);
+				ep->state = STATUS_STAGE_TEST;
+				udc->test_mode = le16_to_cpu(crq->wIndex);
+				return 0;
+			} else if (feature_is_dev_remote_wakeup(crq)) {
+				udc->devstatus |= 1 << USB_DEVICE_REMOTE_WAKEUP;
+			} else {
+				goto stall;
+			}
+		} else if (crq->bRequestType == USB_RECIP_ENDPOINT) {
+			struct usba_ep *target;
+
+			if (crq->wLength != __constant_cpu_to_le16(0)
+					|| !feature_is_ep_halt(crq))
+				goto stall;
+
+			target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex));
+			if (!target)
+				goto stall;
+
+			usba_ep_writel(target, SET_STA, USBA_FORCE_STALL);
+		} else
+			goto delegate;
+
+		send_status(udc, ep);
+		break;
+	}
+
+	case USB_REQ_SET_ADDRESS:
+		if (crq->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE))
+			goto delegate;
+
+		set_address(udc, le16_to_cpu(crq->wValue));
+		send_status(udc, ep);
+		ep->state = STATUS_STAGE_ADDR;
+		break;
+
+	default:
+delegate:
+		spin_unlock(&udc->lock);
+		retval = udc->driver->setup(&udc->gadget, crq);
+		spin_lock(&udc->lock);
+	}
+
+	return retval;
+
+stall:
+	printk(KERN_ERR
+		"udc: %s: Invalid setup request: %02x.%02x v%04x i%04x l%d, "
+		"halting endpoint...\n",
+		ep->ep.name, crq->bRequestType, crq->bRequest,
+		le16_to_cpu(crq->wValue), le16_to_cpu(crq->wIndex),
+		le16_to_cpu(crq->wLength));
+	set_protocol_stall(udc, ep);
+	return -1;
+}
+
+static void usba_control_irq(struct usba_udc *udc, struct usba_ep *ep)
+{
+	struct usba_request *req;
+	u32 epstatus;
+	u32 epctrl;
+
+restart:
+	epstatus = usba_ep_readl(ep, STA);
+	epctrl = usba_ep_readl(ep, CTL);
+
+	DBG(DBG_INT, "%s [%d]: s/%08x c/%08x\n",
+			ep->ep.name, ep->state, epstatus, epctrl);
+
+	req = NULL;
+	if (!list_empty(&ep->queue))
+		req = list_entry(ep->queue.next,
+				 struct usba_request, queue);
+
+	if ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) {
+		if (req->submitted)
+			next_fifo_transaction(ep, req);
+		else
+			submit_request(ep, req);
+
+		if (req->last_transaction) {
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
+			usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
+		}
+		goto restart;
+	}
+	if ((epstatus & epctrl) & USBA_TX_COMPLETE) {
+		usba_ep_writel(ep, CLR_STA, USBA_TX_COMPLETE);
+
+		switch (ep->state) {
+		case DATA_STAGE_IN:
+			usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY);
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+			ep->state = STATUS_STAGE_OUT;
+			break;
+		case STATUS_STAGE_ADDR:
+			/* Activate our new address */
+			usba_writel(udc, CTRL, (usba_readl(udc, CTRL)
+						| USBA_FADDR_EN));
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+			ep->state = WAIT_FOR_SETUP;
+			break;
+		case STATUS_STAGE_IN:
+			if (req) {
+				list_del_init(&req->queue);
+				request_complete(ep, req, 0);
+				submit_next_request(ep);
+			}
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+			ep->state = WAIT_FOR_SETUP;
+			break;
+		case STATUS_STAGE_TEST:
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+			ep->state = WAIT_FOR_SETUP;
+			if (do_test_mode(udc))
+				set_protocol_stall(udc, ep);
+			break;
+		default:
+			printk(KERN_ERR
+				"udc: %s: TXCOMP: Invalid endpoint state %d, "
+				"halting endpoint...\n",
+				ep->ep.name, ep->state);
+			set_protocol_stall(udc, ep);
+			break;
+		}
+
+		goto restart;
+	}
+	if ((epstatus & epctrl) & USBA_RX_BK_RDY) {
+		switch (ep->state) {
+		case STATUS_STAGE_OUT:
+			usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+			usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+
+			if (req) {
+				list_del_init(&req->queue);
+				request_complete(ep, req, 0);
+			}
+			ep->state = WAIT_FOR_SETUP;
+			break;
+
+		case DATA_STAGE_OUT:
+			receive_data(ep);
+			break;
+
+		default:
+			usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+			usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+			printk(KERN_ERR
+				"udc: %s: RXRDY: Invalid endpoint state %d, "
+				"halting endpoint...\n",
+				ep->ep.name, ep->state);
+			set_protocol_stall(udc, ep);
+			break;
+		}
+
+		goto restart;
+	}
+	if (epstatus & USBA_RX_SETUP) {
+		union {
+			struct usb_ctrlrequest crq;
+			unsigned long data[2];
+		} crq;
+		unsigned int pkt_len;
+		int ret;
+
+		if (ep->state != WAIT_FOR_SETUP) {
+			/*
+			 * Didn't expect a SETUP packet at this
+			 * point. Clean up any pending requests (which
+			 * may be successful).
+			 */
+			int status = -EPROTO;
+
+			/*
+			 * RXRDY and TXCOMP are dropped when SETUP
+			 * packets arrive.  Just pretend we received
+			 * the status packet.
+			 */
+			if (ep->state == STATUS_STAGE_OUT
+					|| ep->state == STATUS_STAGE_IN) {
+				usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+				status = 0;
+			}
+
+			if (req) {
+				list_del_init(&req->queue);
+				request_complete(ep, req, status);
+			}
+		}
+
+		pkt_len = USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA));
+		DBG(DBG_HW, "Packet length: %u\n", pkt_len);
+		if (pkt_len != sizeof(crq)) {
+			printk(KERN_WARNING "udc: Invalid packet length %u "
+				"(expected %lu)\n", pkt_len, sizeof(crq));
+			set_protocol_stall(udc, ep);
+			return;
+		}
+
+		DBG(DBG_FIFO, "Copying ctrl request from 0x%p:\n", ep->fifo);
+		copy_from_fifo(crq.data, ep->fifo, sizeof(crq));
+
+		/* Free up one bank in the FIFO so that we can
+		 * generate or receive a reply right away. */
+		usba_ep_writel(ep, CLR_STA, USBA_RX_SETUP);
+
+		/* printk(KERN_DEBUG "setup: %d: %02x.%02x\n",
+			ep->state, crq.crq.bRequestType,
+			crq.crq.bRequest); */
+
+		if (crq.crq.bRequestType & USB_DIR_IN) {
+			/*
+			 * The USB 2.0 spec states that "if wLength is
+			 * zero, there is no data transfer phase."
+			 * However, testusb #14 seems to actually
+			 * expect a data phase even if wLength = 0...
+			 */
+			ep->state = DATA_STAGE_IN;
+		} else {
+			if (crq.crq.wLength != __constant_cpu_to_le16(0))
+				ep->state = DATA_STAGE_OUT;
+			else
+				ep->state = STATUS_STAGE_IN;
+		}
+
+		ret = -1;
+		if (ep->index == 0)
+			ret = handle_ep0_setup(udc, ep, &crq.crq);
+		else {
+			spin_unlock(&udc->lock);
+			ret = udc->driver->setup(&udc->gadget, &crq.crq);
+			spin_lock(&udc->lock);
+		}
+
+		DBG(DBG_BUS, "req %02x.%02x, length %d, state %d, ret %d\n",
+			crq.crq.bRequestType, crq.crq.bRequest,
+			le16_to_cpu(crq.crq.wLength), ep->state, ret);
+
+		if (ret < 0) {
+			/* Let the host know that we failed */
+			set_protocol_stall(udc, ep);
+		}
+	}
+}
+
+static void usba_ep_irq(struct usba_udc *udc, struct usba_ep *ep)
+{
+	struct usba_request *req;
+	u32 epstatus;
+	u32 epctrl;
+
+	epstatus = usba_ep_readl(ep, STA);
+	epctrl = usba_ep_readl(ep, CTL);
+
+	DBG(DBG_INT, "%s: interrupt, status: 0x%08x\n", ep->ep.name, epstatus);
+
+	while ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) {
+		DBG(DBG_BUS, "%s: TX PK ready\n", ep->ep.name);
+
+		if (list_empty(&ep->queue)) {
+			dev_warn(&udc->pdev->dev, "ep_irq: queue empty\n");
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
+			return;
+		}
+
+		req = list_entry(ep->queue.next, struct usba_request, queue);
+
+		if (req->using_dma) {
+			/* Send a zero-length packet */
+			usba_ep_writel(ep, SET_STA,
+					USBA_TX_PK_RDY);
+			usba_ep_writel(ep, CTL_DIS,
+					USBA_TX_PK_RDY);
+			list_del_init(&req->queue);
+			submit_next_request(ep);
+			request_complete(ep, req, 0);
+		} else {
+			if (req->submitted)
+				next_fifo_transaction(ep, req);
+			else
+				submit_request(ep, req);
+
+			if (req->last_transaction) {
+				list_del_init(&req->queue);
+				submit_next_request(ep);
+				request_complete(ep, req, 0);
+			}
+		}
+
+		epstatus = usba_ep_readl(ep, STA);
+		epctrl = usba_ep_readl(ep, CTL);
+	}
+	if ((epstatus & epctrl) & USBA_RX_BK_RDY) {
+		DBG(DBG_BUS, "%s: RX data ready\n", ep->ep.name);
+		receive_data(ep);
+		usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+	}
+}
+
+static void usba_dma_irq(struct usba_udc *udc, struct usba_ep *ep)
+{
+	struct usba_request *req;
+	u32 status, control, pending;
+
+	status = usba_dma_readl(ep, STATUS);
+	control = usba_dma_readl(ep, CONTROL);
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+	ep->last_dma_status = status;
+#endif
+	pending = status & control;
+	DBG(DBG_INT | DBG_DMA, "dma irq, s/%#08x, c/%#08x\n", status, control);
+
+	if (status & USBA_DMA_CH_EN) {
+		dev_err(&udc->pdev->dev,
+			"DMA_CH_EN is set after transfer is finished!\n");
+		dev_err(&udc->pdev->dev,
+			"status=%#08x, pending=%#08x, control=%#08x\n",
+			status, pending, control);
+
+		/*
+		 * try to pretend nothing happened. We might have to
+		 * do something here...
+		 */
+	}
+
+	if (list_empty(&ep->queue))
+		/* Might happen if a reset comes along at the right moment */
+		return;
+
+	if (pending & (USBA_DMA_END_TR_ST | USBA_DMA_END_BUF_ST)) {
+		req = list_entry(ep->queue.next, struct usba_request, queue);
+		usba_update_req(ep, req, status);
+
+		list_del_init(&req->queue);
+		submit_next_request(ep);
+		request_complete(ep, req, 0);
+	}
+}
+
+static irqreturn_t usba_udc_irq(int irq, void *devid)
+{
+	struct usba_udc *udc = devid;
+	u32 status;
+	u32 dma_status;
+	u32 ep_status;
+
+	spin_lock(&udc->lock);
+
+	status = usba_readl(udc, INT_STA);
+	DBG(DBG_INT, "irq, status=%#08x\n", status);
+
+	if (status & USBA_DET_SUSPEND) {
+		usba_writel(udc, INT_CLR, USBA_DET_SUSPEND);
+		DBG(DBG_BUS, "Suspend detected\n");
+		if (udc->gadget.speed != USB_SPEED_UNKNOWN
+				&& udc->driver && udc->driver->suspend) {
+			spin_unlock(&udc->lock);
+			udc->driver->suspend(&udc->gadget);
+			spin_lock(&udc->lock);
+		}
+	}
+
+	if (status & USBA_WAKE_UP) {
+		usba_writel(udc, INT_CLR, USBA_WAKE_UP);
+		DBG(DBG_BUS, "Wake Up CPU detected\n");
+	}
+
+	if (status & USBA_END_OF_RESUME) {
+		usba_writel(udc, INT_CLR, USBA_END_OF_RESUME);
+		DBG(DBG_BUS, "Resume detected\n");
+		if (udc->gadget.speed != USB_SPEED_UNKNOWN
+				&& udc->driver && udc->driver->resume) {
+			spin_unlock(&udc->lock);
+			udc->driver->resume(&udc->gadget);
+			spin_lock(&udc->lock);
+		}
+	}
+
+	dma_status = USBA_BFEXT(DMA_INT, status);
+	if (dma_status) {
+		int i;
+
+		for (i = 1; i < USBA_NR_ENDPOINTS; i++)
+			if (dma_status & (1 << i))
+				usba_dma_irq(udc, &usba_ep[i]);
+	}
+
+	ep_status = USBA_BFEXT(EPT_INT, status);
+	if (ep_status) {
+		int i;
+
+		for (i = 0; i < USBA_NR_ENDPOINTS; i++)
+			if (ep_status & (1 << i)) {
+				if (ep_is_control(&usba_ep[i]))
+					usba_control_irq(udc, &usba_ep[i]);
+				else
+					usba_ep_irq(udc, &usba_ep[i]);
+			}
+	}
+
+	if (status & USBA_END_OF_RESET) {
+		struct usba_ep *ep0;
+
+		usba_writel(udc, INT_CLR, USBA_END_OF_RESET);
+		reset_all_endpoints(udc);
+
+		if (status & USBA_HIGH_SPEED) {
+			DBG(DBG_BUS, "High-speed bus reset detected\n");
+			udc->gadget.speed = USB_SPEED_HIGH;
+		} else {
+			DBG(DBG_BUS, "Full-speed bus reset detected\n");
+			udc->gadget.speed = USB_SPEED_FULL;
+		}
+
+		ep0 = &usba_ep[0];
+		ep0->desc = &usba_ep0_desc;
+		ep0->state = WAIT_FOR_SETUP;
+		usba_ep_writel(ep0, CFG,
+				(USBA_BF(EPT_SIZE, EP0_EPT_SIZE)
+				| USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL)
+				| USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE)));
+		usba_ep_writel(ep0, CTL_ENB,
+				USBA_EPT_ENABLE | USBA_RX_SETUP);
+		usba_writel(udc, INT_ENB,
+				(usba_readl(udc, INT_ENB)
+				| USBA_BF(EPT_INT, 1)
+				| USBA_DET_SUSPEND
+				| USBA_END_OF_RESUME));
+
+		if (!(usba_ep_readl(ep0, CFG) & USBA_EPT_MAPPED))
+			dev_warn(&udc->pdev->dev,
+				 "WARNING: EP0 configuration is invalid!\n");
+	}
+
+	spin_unlock(&udc->lock);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t usba_vbus_irq(int irq, void *devid)
+{
+	struct usba_udc *udc = devid;
+	int vbus;
+
+	/* debounce */
+	udelay(10);
+
+	spin_lock(&udc->lock);
+
+	/* May happen if Vbus pin toggles during probe() */
+	if (!udc->driver)
+		goto out;
+
+	vbus = gpio_get_value(udc->vbus_pin);
+	if (vbus != udc->vbus_prev) {
+		if (vbus) {
+			usba_writel(udc, CTRL, USBA_EN_USBA);
+			usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
+		} else {
+			udc->gadget.speed = USB_SPEED_UNKNOWN;
+			reset_all_endpoints(udc);
+			usba_writel(udc, CTRL, 0);
+			spin_unlock(&udc->lock);
+			udc->driver->disconnect(&udc->gadget);
+			spin_lock(&udc->lock);
+		}
+		udc->vbus_prev = vbus;
+	}
+
+out:
+	spin_unlock(&udc->lock);
+
+	return IRQ_HANDLED;
+}
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	struct usba_udc *udc = &the_udc;
+	unsigned long flags;
+	int ret;
+
+	if (!udc->pdev)
+		return -ENODEV;
+
+	spin_lock_irqsave(&udc->lock, flags);
+	if (udc->driver) {
+		spin_unlock_irqrestore(&udc->lock, flags);
+		return -EBUSY;
+	}
+
+	udc->devstatus = 1 << USB_DEVICE_SELF_POWERED;
+	udc->driver = driver;
+	udc->gadget.dev.driver = &driver->driver;
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	clk_enable(udc->pclk);
+	clk_enable(udc->hclk);
+
+	ret = driver->bind(&udc->gadget);
+	if (ret) {
+		DBG(DBG_ERR, "Could not bind to driver %s: error %d\n",
+			driver->driver.name, ret);
+		goto err_driver_bind;
+	}
+
+	DBG(DBG_GADGET, "registered driver `%s'\n", driver->driver.name);
+
+	udc->vbus_prev = 0;
+	if (udc->vbus_pin != -1)
+		enable_irq(gpio_to_irq(udc->vbus_pin));
+
+	/* If Vbus is present, enable the controller and wait for reset */
+	spin_lock_irqsave(&udc->lock, flags);
+	if (vbus_is_present(udc) && udc->vbus_prev == 0) {
+		usba_writel(udc, CTRL, USBA_EN_USBA);
+		usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
+	}
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return 0;
+
+err_driver_bind:
+	udc->driver = NULL;
+	udc->gadget.dev.driver = NULL;
+	return ret;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct usba_udc *udc = &the_udc;
+	unsigned long flags;
+
+	if (!udc->pdev)
+		return -ENODEV;
+	if (driver != udc->driver)
+		return -EINVAL;
+
+	if (udc->vbus_pin != -1)
+		disable_irq(gpio_to_irq(udc->vbus_pin));
+
+	spin_lock_irqsave(&udc->lock, flags);
+	udc->gadget.speed = USB_SPEED_UNKNOWN;
+	reset_all_endpoints(udc);
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	/* This will also disable the DP pullup */
+	usba_writel(udc, CTRL, 0);
+
+	driver->unbind(&udc->gadget);
+	udc->gadget.dev.driver = NULL;
+	udc->driver = NULL;
+
+	clk_disable(udc->hclk);
+	clk_disable(udc->pclk);
+
+	DBG(DBG_GADGET, "unregistered driver `%s'\n", driver->driver.name);
+
+	return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+static int __init usba_udc_probe(struct platform_device *pdev)
+{
+	struct usba_platform_data *pdata = pdev->dev.platform_data;
+	struct resource *regs, *fifo;
+	struct clk *pclk, *hclk;
+	struct usba_udc *udc = &the_udc;
+	int irq, ret, i;
+
+	regs = platform_get_resource(pdev, IORESOURCE_MEM, CTRL_IOMEM_ID);
+	fifo = platform_get_resource(pdev, IORESOURCE_MEM, FIFO_IOMEM_ID);
+	if (!regs || !fifo)
+		return -ENXIO;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	pclk = clk_get(&pdev->dev, "pclk");
+	if (IS_ERR(pclk))
+		return PTR_ERR(pclk);
+	hclk = clk_get(&pdev->dev, "hclk");
+	if (IS_ERR(hclk)) {
+		ret = PTR_ERR(hclk);
+		goto err_get_hclk;
+	}
+
+	udc->pdev = pdev;
+	udc->pclk = pclk;
+	udc->hclk = hclk;
+	udc->vbus_pin = -1;
+
+	ret = -ENOMEM;
+	udc->regs = ioremap(regs->start, regs->end - regs->start + 1);
+	if (!udc->regs) {
+		dev_err(&pdev->dev, "Unable to map I/O memory, aborting.\n");
+		goto err_map_regs;
+	}
+	dev_info(&pdev->dev, "MMIO registers at 0x%08lx mapped at %p\n",
+		 (unsigned long)regs->start, udc->regs);
+	udc->fifo = ioremap(fifo->start, fifo->end - fifo->start + 1);
+	if (!udc->fifo) {
+		dev_err(&pdev->dev, "Unable to map FIFO, aborting.\n");
+		goto err_map_fifo;
+	}
+	dev_info(&pdev->dev, "FIFO at 0x%08lx mapped at %p\n",
+		 (unsigned long)fifo->start, udc->fifo);
+
+	device_initialize(&udc->gadget.dev);
+	udc->gadget.dev.parent = &pdev->dev;
+	udc->gadget.dev.dma_mask = pdev->dev.dma_mask;
+
+	platform_set_drvdata(pdev, udc);
+
+	/* Make sure we start from a clean slate */
+	clk_enable(pclk);
+	usba_writel(udc, CTRL, 0);
+	clk_disable(pclk);
+
+	INIT_LIST_HEAD(&usba_ep[0].ep.ep_list);
+	usba_ep[0].ep_regs = udc->regs + USBA_EPT_BASE(0);
+	usba_ep[0].dma_regs = udc->regs + USBA_DMA_BASE(0);
+	usba_ep[0].fifo = udc->fifo + USBA_FIFO_BASE(0);
+	for (i = 1; i < ARRAY_SIZE(usba_ep); i++) {
+		struct usba_ep *ep = &usba_ep[i];
+
+		ep->ep_regs = udc->regs + USBA_EPT_BASE(i);
+		ep->dma_regs = udc->regs + USBA_DMA_BASE(i);
+		ep->fifo = udc->fifo + USBA_FIFO_BASE(i);
+
+		list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+	}
+
+	ret = request_irq(irq, usba_udc_irq, 0, "atmel_usba_udc", udc);
+	if (ret) {
+		dev_err(&pdev->dev, "Cannot request irq %d (error %d)\n",
+			irq, ret);
+		goto err_request_irq;
+	}
+	udc->irq = irq;
+
+	ret = device_add(&udc->gadget.dev);
+	if (ret) {
+		dev_dbg(&pdev->dev, "Could not add gadget: %d\n", ret);
+		goto err_device_add;
+	}
+
+	if (pdata && pdata->vbus_pin != GPIO_PIN_NONE) {
+		if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) {
+			udc->vbus_pin = pdata->vbus_pin;
+
+			ret = request_irq(gpio_to_irq(udc->vbus_pin),
+					usba_vbus_irq, 0,
+					"atmel_usba_udc", udc);
+			if (ret) {
+				gpio_free(udc->vbus_pin);
+				udc->vbus_pin = -1;
+				dev_warn(&udc->pdev->dev,
+					 "failed to request vbus irq; "
+					 "assuming always on\n");
+			} else {
+				disable_irq(gpio_to_irq(udc->vbus_pin));
+			}
+		}
+	}
+
+	usba_init_debugfs(udc);
+	for (i = 1; i < ARRAY_SIZE(usba_ep); i++)
+		usba_ep_init_debugfs(udc, &usba_ep[i]);
+
+	return 0;
+
+err_device_add:
+	free_irq(irq, udc);
+err_request_irq:
+	iounmap(udc->fifo);
+err_map_fifo:
+	iounmap(udc->regs);
+err_map_regs:
+	clk_put(hclk);
+err_get_hclk:
+	clk_put(pclk);
+
+	platform_set_drvdata(pdev, NULL);
+
+	return ret;
+}
+
+static int __exit usba_udc_remove(struct platform_device *pdev)
+{
+	struct usba_udc *udc;
+	int i;
+
+	udc = platform_get_drvdata(pdev);
+
+	for (i = 1; i < ARRAY_SIZE(usba_ep); i++)
+		usba_ep_cleanup_debugfs(&usba_ep[i]);
+	usba_cleanup_debugfs(udc);
+
+	if (udc->vbus_pin != -1)
+		gpio_free(udc->vbus_pin);
+
+	free_irq(udc->irq, udc);
+	iounmap(udc->fifo);
+	iounmap(udc->regs);
+	clk_put(udc->hclk);
+	clk_put(udc->pclk);
+
+	device_unregister(&udc->gadget.dev);
+
+	return 0;
+}
+
+static struct platform_driver udc_driver = {
+	.remove		= __exit_p(usba_udc_remove),
+	.driver		= {
+		.name		= "atmel_usba_udc",
+	},
+};
+
+static int __init udc_init(void)
+{
+	return platform_driver_probe(&udc_driver, usba_udc_probe);
+}
+module_init(udc_init);
+
+static void __exit udc_exit(void)
+{
+	platform_driver_unregister(&udc_driver);
+}
+module_exit(udc_exit);
+
+MODULE_DESCRIPTION("Atmel USBA UDC driver");
+MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/atmel_usba_udc.h
new file mode 100644
index 0000000..a68304e
--- /dev/null
+++ b/drivers/usb/gadget/atmel_usba_udc.h
@@ -0,0 +1,352 @@
+/*
+ * Driver for the Atmel USBA high speed USB device controller
+ *
+ * Copyright (C) 2005-2007 Atmel 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.
+ */
+#ifndef __LINUX_USB_GADGET_USBA_UDC_H__
+#define __LINUX_USB_GADGET_USBA_UDC_H__
+
+/* USB register offsets */
+#define USBA_CTRL				0x0000
+#define USBA_FNUM				0x0004
+#define USBA_INT_ENB				0x0010
+#define USBA_INT_STA				0x0014
+#define USBA_INT_CLR				0x0018
+#define USBA_EPT_RST				0x001c
+#define USBA_TST				0x00e0
+
+/* USB endpoint register offsets */
+#define USBA_EPT_CFG				0x0000
+#define USBA_EPT_CTL_ENB			0x0004
+#define USBA_EPT_CTL_DIS			0x0008
+#define USBA_EPT_CTL				0x000c
+#define USBA_EPT_SET_STA			0x0014
+#define USBA_EPT_CLR_STA			0x0018
+#define USBA_EPT_STA				0x001c
+
+/* USB DMA register offsets */
+#define USBA_DMA_NXT_DSC			0x0000
+#define USBA_DMA_ADDRESS			0x0004
+#define USBA_DMA_CONTROL			0x0008
+#define USBA_DMA_STATUS				0x000c
+
+/* Bitfields in CTRL */
+#define USBA_DEV_ADDR_OFFSET			0
+#define USBA_DEV_ADDR_SIZE			7
+#define USBA_FADDR_EN				(1 <<  7)
+#define USBA_EN_USBA				(1 <<  8)
+#define USBA_DETACH				(1 <<  9)
+#define USBA_REMOTE_WAKE_UP			(1 << 10)
+
+/* Bitfields in FNUM */
+#define USBA_MICRO_FRAME_NUM_OFFSET		0
+#define USBA_MICRO_FRAME_NUM_SIZE		3
+#define USBA_FRAME_NUMBER_OFFSET		3
+#define USBA_FRAME_NUMBER_SIZE			11
+#define USBA_FRAME_NUM_ERROR			(1 << 31)
+
+/* Bitfields in INT_ENB/INT_STA/INT_CLR */
+#define USBA_HIGH_SPEED				(1 <<  0)
+#define USBA_DET_SUSPEND			(1 <<  1)
+#define USBA_MICRO_SOF				(1 <<  2)
+#define USBA_SOF				(1 <<  3)
+#define USBA_END_OF_RESET			(1 <<  4)
+#define USBA_WAKE_UP				(1 <<  5)
+#define USBA_END_OF_RESUME			(1 <<  6)
+#define USBA_UPSTREAM_RESUME			(1 <<  7)
+#define USBA_EPT_INT_OFFSET			8
+#define USBA_EPT_INT_SIZE			16
+#define USBA_DMA_INT_OFFSET			24
+#define USBA_DMA_INT_SIZE			8
+
+/* Bitfields in EPT_RST */
+#define USBA_RST_OFFSET				0
+#define USBA_RST_SIZE				16
+
+/* Bitfields in USBA_TST */
+#define USBA_SPEED_CFG_OFFSET			0
+#define USBA_SPEED_CFG_SIZE			2
+#define USBA_TST_J_MODE				(1 <<  2)
+#define USBA_TST_K_MODE				(1 <<  3)
+#define USBA_TST_PKT_MODE			(1 <<  4)
+#define USBA_OPMODE2				(1 <<  5)
+
+/* Bitfields in EPT_CFG */
+#define USBA_EPT_SIZE_OFFSET			0
+#define USBA_EPT_SIZE_SIZE			3
+#define USBA_EPT_DIR_IN				(1 <<  3)
+#define USBA_EPT_TYPE_OFFSET			4
+#define USBA_EPT_TYPE_SIZE			2
+#define USBA_BK_NUMBER_OFFSET			6
+#define USBA_BK_NUMBER_SIZE			2
+#define USBA_NB_TRANS_OFFSET			8
+#define USBA_NB_TRANS_SIZE			2
+#define USBA_EPT_MAPPED				(1 << 31)
+
+/* Bitfields in EPT_CTL/EPT_CTL_ENB/EPT_CTL_DIS */
+#define USBA_EPT_ENABLE				(1 <<  0)
+#define USBA_AUTO_VALID				(1 <<  1)
+#define USBA_INTDIS_DMA				(1 <<  3)
+#define USBA_NYET_DIS				(1 <<  4)
+#define USBA_DATAX_RX				(1 <<  6)
+#define USBA_MDATA_RX				(1 <<  7)
+/* Bits 8-15 and 31 enable interrupts for respective bits in EPT_STA */
+#define USBA_BUSY_BANK_IE			(1 << 18)
+
+/* Bitfields in EPT_SET_STA/EPT_CLR_STA/EPT_STA */
+#define USBA_FORCE_STALL			(1 <<  5)
+#define USBA_TOGGLE_CLR				(1 <<  6)
+#define USBA_TOGGLE_SEQ_OFFSET			6
+#define USBA_TOGGLE_SEQ_SIZE			2
+#define USBA_ERR_OVFLW				(1 <<  8)
+#define USBA_RX_BK_RDY				(1 <<  9)
+#define USBA_KILL_BANK				(1 <<  9)
+#define USBA_TX_COMPLETE			(1 << 10)
+#define USBA_TX_PK_RDY				(1 << 11)
+#define USBA_ISO_ERR_TRANS			(1 << 11)
+#define USBA_RX_SETUP				(1 << 12)
+#define USBA_ISO_ERR_FLOW			(1 << 12)
+#define USBA_STALL_SENT				(1 << 13)
+#define USBA_ISO_ERR_CRC			(1 << 13)
+#define USBA_ISO_ERR_NBTRANS			(1 << 13)
+#define USBA_NAK_IN				(1 << 14)
+#define USBA_ISO_ERR_FLUSH			(1 << 14)
+#define USBA_NAK_OUT				(1 << 15)
+#define USBA_CURRENT_BANK_OFFSET		16
+#define USBA_CURRENT_BANK_SIZE			2
+#define USBA_BUSY_BANKS_OFFSET			18
+#define USBA_BUSY_BANKS_SIZE			2
+#define USBA_BYTE_COUNT_OFFSET			20
+#define USBA_BYTE_COUNT_SIZE			11
+#define USBA_SHORT_PACKET			(1 << 31)
+
+/* Bitfields in DMA_CONTROL */
+#define USBA_DMA_CH_EN				(1 <<  0)
+#define USBA_DMA_LINK				(1 <<  1)
+#define USBA_DMA_END_TR_EN			(1 <<  2)
+#define USBA_DMA_END_BUF_EN			(1 <<  3)
+#define USBA_DMA_END_TR_IE			(1 <<  4)
+#define USBA_DMA_END_BUF_IE			(1 <<  5)
+#define USBA_DMA_DESC_LOAD_IE			(1 <<  6)
+#define USBA_DMA_BURST_LOCK			(1 <<  7)
+#define USBA_DMA_BUF_LEN_OFFSET			16
+#define USBA_DMA_BUF_LEN_SIZE			16
+
+/* Bitfields in DMA_STATUS */
+#define USBA_DMA_CH_ACTIVE			(1 <<  1)
+#define USBA_DMA_END_TR_ST			(1 <<  4)
+#define USBA_DMA_END_BUF_ST			(1 <<  5)
+#define USBA_DMA_DESC_LOAD_ST			(1 <<  6)
+
+/* Constants for SPEED_CFG */
+#define USBA_SPEED_CFG_NORMAL			0
+#define USBA_SPEED_CFG_FORCE_HIGH		2
+#define USBA_SPEED_CFG_FORCE_FULL		3
+
+/* Constants for EPT_SIZE */
+#define USBA_EPT_SIZE_8				0
+#define USBA_EPT_SIZE_16			1
+#define USBA_EPT_SIZE_32			2
+#define USBA_EPT_SIZE_64			3
+#define USBA_EPT_SIZE_128			4
+#define USBA_EPT_SIZE_256			5
+#define USBA_EPT_SIZE_512			6
+#define USBA_EPT_SIZE_1024			7
+
+/* Constants for EPT_TYPE */
+#define USBA_EPT_TYPE_CONTROL			0
+#define USBA_EPT_TYPE_ISO			1
+#define USBA_EPT_TYPE_BULK			2
+#define USBA_EPT_TYPE_INT			3
+
+/* Constants for BK_NUMBER */
+#define USBA_BK_NUMBER_ZERO			0
+#define USBA_BK_NUMBER_ONE			1
+#define USBA_BK_NUMBER_DOUBLE			2
+#define USBA_BK_NUMBER_TRIPLE			3
+
+/* Bit manipulation macros */
+#define USBA_BF(name, value)					\
+	(((value) & ((1 << USBA_##name##_SIZE) - 1))		\
+	 << USBA_##name##_OFFSET)
+#define USBA_BFEXT(name, value)					\
+	(((value) >> USBA_##name##_OFFSET)			\
+	 & ((1 << USBA_##name##_SIZE) - 1))
+#define USBA_BFINS(name, value, old)				\
+	(((old) & ~(((1 << USBA_##name##_SIZE) - 1)		\
+		    << USBA_##name##_OFFSET))			\
+	 | USBA_BF(name, value))
+
+/* Register access macros */
+#define usba_readl(udc, reg)					\
+	__raw_readl((udc)->regs + USBA_##reg)
+#define usba_writel(udc, reg, value)				\
+	__raw_writel((value), (udc)->regs + USBA_##reg)
+#define usba_ep_readl(ep, reg)					\
+	__raw_readl((ep)->ep_regs + USBA_EPT_##reg)
+#define usba_ep_writel(ep, reg, value)				\
+	__raw_writel((value), (ep)->ep_regs + USBA_EPT_##reg)
+#define usba_dma_readl(ep, reg)					\
+	__raw_readl((ep)->dma_regs + USBA_DMA_##reg)
+#define usba_dma_writel(ep, reg, value)				\
+	__raw_writel((value), (ep)->dma_regs + USBA_DMA_##reg)
+
+/* Calculate base address for a given endpoint or DMA controller */
+#define USBA_EPT_BASE(x)	(0x100 + (x) * 0x20)
+#define USBA_DMA_BASE(x)	(0x300 + (x) * 0x10)
+#define USBA_FIFO_BASE(x)	((x) << 16)
+
+/* Synth parameters */
+#define USBA_NR_ENDPOINTS	7
+
+#define EP0_FIFO_SIZE		64
+#define EP0_EPT_SIZE		USBA_EPT_SIZE_64
+#define EP0_NR_BANKS		1
+
+/*
+ * REVISIT: Try to eliminate this value. Can we rely on req->mapped to
+ * provide this information?
+ */
+#define DMA_ADDR_INVALID (~(dma_addr_t)0)
+
+#define FIFO_IOMEM_ID	0
+#define CTRL_IOMEM_ID	1
+
+#ifdef DEBUG
+#define DBG_ERR		0x0001	/* report all error returns */
+#define DBG_HW		0x0002	/* debug hardware initialization */
+#define DBG_GADGET	0x0004	/* calls to/from gadget driver */
+#define DBG_INT		0x0008	/* interrupts */
+#define DBG_BUS		0x0010	/* report changes in bus state */
+#define DBG_QUEUE	0x0020  /* debug request queue processing */
+#define DBG_FIFO	0x0040  /* debug FIFO contents */
+#define DBG_DMA		0x0080  /* debug DMA handling */
+#define DBG_REQ		0x0100	/* print out queued request length */
+#define DBG_ALL		0xffff
+#define DBG_NONE	0x0000
+
+#define DEBUG_LEVEL	(DBG_ERR)
+#define DBG(level, fmt, ...)					\
+	do {							\
+		if ((level) & DEBUG_LEVEL)			\
+			printk(KERN_DEBUG "udc: " fmt, ## __VA_ARGS__);	\
+	} while (0)
+#else
+#define DBG(level, fmt...)
+#endif
+
+enum usba_ctrl_state {
+	WAIT_FOR_SETUP,
+	DATA_STAGE_IN,
+	DATA_STAGE_OUT,
+	STATUS_STAGE_IN,
+	STATUS_STAGE_OUT,
+	STATUS_STAGE_ADDR,
+	STATUS_STAGE_TEST,
+};
+/*
+  EP_STATE_IDLE,
+  EP_STATE_SETUP,
+  EP_STATE_IN_DATA,
+  EP_STATE_OUT_DATA,
+  EP_STATE_SET_ADDR_STATUS,
+  EP_STATE_RX_STATUS,
+  EP_STATE_TX_STATUS,
+  EP_STATE_HALT,
+*/
+
+struct usba_dma_desc {
+	dma_addr_t next;
+	dma_addr_t addr;
+	u32 ctrl;
+};
+
+struct usba_ep {
+	int					state;
+	void __iomem				*ep_regs;
+	void __iomem				*dma_regs;
+	void __iomem				*fifo;
+	struct usb_ep				ep;
+	struct usba_udc				*udc;
+
+	struct list_head			queue;
+	const struct usb_endpoint_descriptor	*desc;
+
+	u16					fifo_size;
+	u8					nr_banks;
+	u8					index;
+	unsigned int				can_dma:1;
+	unsigned int				can_isoc:1;
+	unsigned int				is_isoc:1;
+	unsigned int				is_in:1;
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+	u32					last_dma_status;
+	struct dentry				*debugfs_dir;
+	struct dentry				*debugfs_queue;
+	struct dentry				*debugfs_dma_status;
+	struct dentry				*debugfs_state;
+#endif
+};
+
+struct usba_request {
+	struct usb_request			req;
+	struct list_head			queue;
+
+	u32					ctrl;
+
+	unsigned int				submitted:1;
+	unsigned int				last_transaction:1;
+	unsigned int				using_dma:1;
+	unsigned int				mapped:1;
+};
+
+struct usba_udc {
+	/* Protect hw registers from concurrent modifications */
+	spinlock_t lock;
+
+	void __iomem *regs;
+	void __iomem *fifo;
+
+	struct usb_gadget gadget;
+	struct usb_gadget_driver *driver;
+	struct platform_device *pdev;
+	int irq;
+	int vbus_pin;
+	struct clk *pclk;
+	struct clk *hclk;
+
+	u16 devstatus;
+
+	u16 test_mode;
+	int vbus_prev;
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+	struct dentry *debugfs_root;
+	struct dentry *debugfs_regs;
+#endif
+};
+
+static inline struct usba_ep *to_usba_ep(struct usb_ep *ep)
+{
+	return container_of(ep, struct usba_ep, ep);
+}
+
+static inline struct usba_request *to_usba_req(struct usb_request *req)
+{
+	return container_of(req, struct usba_request, req);
+}
+
+static inline struct usba_udc *to_usba_udc(struct usb_gadget *gadget)
+{
+	return container_of(gadget, struct usba_udc, gadget);
+}
+
+#define ep_is_control(ep)	((ep)->index == 0)
+#define ep_is_idle(ep)		((ep)->state == EP_STATE_IDLE)
+
+#endif /* __LINUX_USB_GADGET_USBA_UDC_H */
diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c
index c6760ae..a4e54b2 100644
--- a/drivers/usb/gadget/config.c
+++ b/drivers/usb/gadget/config.c
@@ -25,7 +25,7 @@
 #include <linux/device.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 
 /**
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index d008d13..9db2482 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -46,7 +46,7 @@
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/usb.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
@@ -962,13 +962,13 @@
 
 static int dummy_urb_enqueue (
 	struct usb_hcd			*hcd,
-	struct usb_host_endpoint	*ep,
 	struct urb			*urb,
 	gfp_t				mem_flags
 ) {
 	struct dummy	*dum;
 	struct urbp	*urbp;
 	unsigned long	flags;
+	int		rc;
 
 	if (!urb->transfer_buffer && urb->transfer_buffer_length)
 		return -EINVAL;
@@ -980,6 +980,11 @@
 
 	dum = hcd_to_dummy (hcd);
 	spin_lock_irqsave (&dum->lock, flags);
+	rc = usb_hcd_link_urb_to_ep(hcd, urb);
+	if (rc) {
+		kfree(urbp);
+		goto done;
+	}
 
 	if (!dum->udev) {
 		dum->udev = urb->dev;
@@ -996,36 +1001,35 @@
 	if (!timer_pending (&dum->timer))
 		mod_timer (&dum->timer, jiffies + 1);
 
-	spin_unlock_irqrestore (&dum->lock, flags);
-	return 0;
+ done:
+	spin_unlock_irqrestore(&dum->lock, flags);
+	return rc;
 }
 
-static int dummy_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
 	struct dummy	*dum;
 	unsigned long	flags;
+	int		rc;
 
 	/* giveback happens automatically in timer callback,
 	 * so make sure the callback happens */
 	dum = hcd_to_dummy (hcd);
 	spin_lock_irqsave (&dum->lock, flags);
-	if (dum->rh_state != DUMMY_RH_RUNNING && !list_empty(&dum->urbp_list))
-		mod_timer (&dum->timer, jiffies);
-	spin_unlock_irqrestore (&dum->lock, flags);
-	return 0;
-}
 
-static void maybe_set_status (struct urb *urb, int status)
-{
-	spin_lock (&urb->lock);
-	if (urb->status == -EINPROGRESS)
-		urb->status = status;
-	spin_unlock (&urb->lock);
+	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (!rc && dum->rh_state != DUMMY_RH_RUNNING &&
+			!list_empty(&dum->urbp_list))
+		mod_timer (&dum->timer, jiffies);
+
+	spin_unlock_irqrestore (&dum->lock, flags);
+	return rc;
 }
 
 /* transfer up to a frame's worth; caller must own lock */
 static int
-transfer (struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit)
+transfer(struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit,
+		int *status)
 {
 	struct dummy_request	*req;
 
@@ -1088,24 +1092,20 @@
 		 *
 		 * partially filling a buffer optionally blocks queue advances
 		 * (so completion handlers can clean up the queue) but we don't
-		 * need to emulate such data-in-flight.  so we only show part
-		 * of the URB_SHORT_NOT_OK effect: completion status.
+		 * need to emulate such data-in-flight.
 		 */
 		if (is_short) {
 			if (host_len == dev_len) {
 				req->req.status = 0;
-				maybe_set_status (urb, 0);
+				*status = 0;
 			} else if (to_host) {
 				req->req.status = 0;
 				if (dev_len > host_len)
-					maybe_set_status (urb, -EOVERFLOW);
+					*status = -EOVERFLOW;
 				else
-					maybe_set_status (urb,
-						(urb->transfer_flags
-							& URB_SHORT_NOT_OK)
-						? -EREMOTEIO : 0);
+					*status = 0;
 			} else if (!to_host) {
-				maybe_set_status (urb, 0);
+				*status = 0;
 				if (host_len > dev_len)
 					req->req.status = -EOVERFLOW;
 				else
@@ -1119,9 +1119,8 @@
 				req->req.status = 0;
 			if (urb->transfer_buffer_length == urb->actual_length
 					&& !(urb->transfer_flags
-						& URB_ZERO_PACKET)) {
-				maybe_set_status (urb, 0);
-			}
+						& URB_ZERO_PACKET))
+				*status = 0;
 		}
 
 		/* device side completion --> continuable */
@@ -1137,7 +1136,7 @@
 		}
 
 		/* host side completion --> terminate */
-		if (urb->status != -EINPROGRESS)
+		if (*status != -EINPROGRESS)
 			break;
 
 		/* rescan to continue with any other queued i/o */
@@ -1248,12 +1247,12 @@
 		u8			address;
 		struct dummy_ep		*ep = NULL;
 		int			type;
+		int			status = -EINPROGRESS;
 
 		urb = urbp->urb;
-		if (urb->status != -EINPROGRESS) {
-			/* likely it was just unlinked */
+		if (urb->unlinked)
 			goto return_urb;
-		} else if (dum->rh_state != DUMMY_RH_RUNNING)
+		else if (dum->rh_state != DUMMY_RH_RUNNING)
 			continue;
 		type = usb_pipetype (urb->pipe);
 
@@ -1274,7 +1273,7 @@
 			dev_dbg (dummy_dev(dum),
 				"no ep configured for urb %p\n",
 				urb);
-			maybe_set_status (urb, -EPROTO);
+			status = -EPROTO;
 			goto return_urb;
 		}
 
@@ -1289,7 +1288,7 @@
 			/* NOTE: must not be iso! */
 			dev_dbg (dummy_dev(dum), "ep %s halted, urb %p\n",
 					ep->ep.name, urb);
-			maybe_set_status (urb, -EPIPE);
+			status = -EPIPE;
 			goto return_urb;
 		}
 		/* FIXME make sure both ends agree on maxpacket */
@@ -1307,7 +1306,7 @@
 			w_value = le16_to_cpu(setup.wValue);
 			if (le16_to_cpu(setup.wLength) !=
 					urb->transfer_buffer_length) {
-				maybe_set_status (urb, -EOVERFLOW);
+				status = -EOVERFLOW;
 				goto return_urb;
 			}
 
@@ -1337,7 +1336,7 @@
 				if (setup.bRequestType != Dev_Request)
 					break;
 				dum->address = w_value;
-				maybe_set_status (urb, 0);
+				status = 0;
 				dev_dbg (udc_dev(dum), "set_address = %d\n",
 						w_value);
 				value = 0;
@@ -1364,7 +1363,7 @@
 					if (value == 0) {
 						dum->devstatus |=
 							(1 << w_value);
-						maybe_set_status (urb, 0);
+						status = 0;
 					}
 
 				} else if (setup.bRequestType == Ep_Request) {
@@ -1376,7 +1375,7 @@
 					}
 					ep2->halted = 1;
 					value = 0;
-					maybe_set_status (urb, 0);
+					status = 0;
 				}
 				break;
 			case USB_REQ_CLEAR_FEATURE:
@@ -1386,7 +1385,7 @@
 						dum->devstatus &= ~(1 <<
 							USB_DEVICE_REMOTE_WAKEUP);
 						value = 0;
-						maybe_set_status (urb, 0);
+						status = 0;
 						break;
 					default:
 						value = -EOPNOTSUPP;
@@ -1401,7 +1400,7 @@
 					}
 					ep2->halted = 0;
 					value = 0;
-					maybe_set_status (urb, 0);
+					status = 0;
 				}
 				break;
 			case USB_REQ_GET_STATUS:
@@ -1438,7 +1437,7 @@
 					urb->actual_length = min (2,
 						urb->transfer_buffer_length);
 					value = 0;
-					maybe_set_status (urb, 0);
+					status = 0;
 				}
 				break;
 			}
@@ -1465,7 +1464,7 @@
 					dev_dbg (udc_dev(dum),
 						"setup --> %d\n",
 						value);
-				maybe_set_status (urb, -EPIPE);
+				status = -EPIPE;
 				urb->actual_length = 0;
 			}
 
@@ -1482,7 +1481,7 @@
 			 * report random errors, to debug drivers.
 			 */
 			limit = max (limit, periodic_bytes (dum, ep));
-			maybe_set_status (urb, -ENOSYS);
+			status = -ENOSYS;
 			break;
 
 		case PIPE_INTERRUPT:
@@ -1496,23 +1495,23 @@
 		default:
 		treat_control_like_bulk:
 			ep->last_io = jiffies;
-			total = transfer (dum, urb, ep, limit);
+			total = transfer(dum, urb, ep, limit, &status);
 			break;
 		}
 
 		/* incomplete transfer? */
-		if (urb->status == -EINPROGRESS)
+		if (status == -EINPROGRESS)
 			continue;
 
 return_urb:
-		urb->hcpriv = NULL;
 		list_del (&urbp->urbp_list);
 		kfree (urbp);
 		if (ep)
 			ep->already_seen = ep->setup_stage = 0;
 
+		usb_hcd_unlink_urb_from_ep(dummy_to_hcd(dum), urb);
 		spin_unlock (&dum->lock);
-		usb_hcd_giveback_urb (dummy_to_hcd(dum), urb);
+		usb_hcd_giveback_urb(dummy_to_hcd(dum), urb, status);
 		spin_lock (&dum->lock);
 
 		goto restart;
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index 3aa46cf..f9d0710 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -28,7 +28,7 @@
 #include <linux/string.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include "gadget_chips.h"
 
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index f700554..9e732bf 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -19,40 +19,18 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+/* #define VERBOSE_DEBUG */
 
-// #define DEBUG 1
-// #define VERBOSE
-
-#include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
 #include <linux/utsname.h>
 #include <linux/device.h>
-#include <linux/moduleparam.h>
 #include <linux/ctype.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/unaligned.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/cdc.h>
-#include <linux/usb_gadget.h>
-
-#include <linux/random.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/ethtool.h>
+#include <linux/usb/gadget.h>
 
 #include "gadget_chips.h"
 
@@ -356,15 +334,15 @@
 #define qlen(gadget) \
 	(DEFAULT_QLEN*((gadget->speed == USB_SPEED_HIGH) ? qmult : 1))
 
-/* also defer IRQs on highspeed TX */
-#define TX_DELAY	qmult
-
 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 qmult		1
+
 #define	DEVSPEED	USB_SPEED_FULL
 
 #define qlen(gadget) DEFAULT_QLEN
@@ -390,7 +368,7 @@
 	do { } while (0)
 #endif /* DEBUG */
 
-#ifdef VERBOSE
+#ifdef VERBOSE_DEBUG
 #define VDEBUG	DEBUG
 #else
 #define VDEBUG(dev,fmt,args...) \
@@ -830,8 +808,6 @@
 };
 #endif
 
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
-
 /*
  * usb 2.0 devices need to expose both high speed and full speed
  * descriptors, unless they only run at full speed.
@@ -934,18 +910,15 @@
 
 
 /* maxpacket and other transfer characteristics vary by speed. */
-#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
-
-#else
-
-/* if there's no high speed support, maxpacket doesn't change. */
-#define ep_desc(g,hs,fs) (((void)(g)), (fs))
-
-static inline void __init hs_subset_descriptors(void)
+static inline struct usb_endpoint_descriptor *
+ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
+		struct usb_endpoint_descriptor *fs)
 {
+	if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+		return hs;
+	return fs;
 }
 
-#endif	/* !CONFIG_USB_GADGET_DUALSPEED */
 
 /*-------------------------------------------------------------------------*/
 
@@ -989,22 +962,19 @@
  * complications: class descriptors, and an altsetting.
  */
 static int
-config_buf (enum usb_device_speed speed,
-	u8 *buf, u8 type,
-	unsigned index, int is_otg)
+config_buf(struct usb_gadget *g, u8 *buf, u8 type, unsigned index, int is_otg)
 {
 	int					len;
 	const struct usb_config_descriptor	*config;
 	const struct usb_descriptor_header	**function;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	int				hs = (speed == USB_SPEED_HIGH);
+	int					hs = 0;
 
-	if (type == USB_DT_OTHER_SPEED_CONFIG)
-		hs = !hs;
+	if (gadget_is_dualspeed(g)) {
+		hs = (g->speed == USB_SPEED_HIGH);
+		if (type == USB_DT_OTHER_SPEED_CONFIG)
+			hs = !hs;
+	}
 #define which_fn(t)	(hs ? hs_ ## t ## _function : fs_ ## t ## _function)
-#else
-#define	which_fn(t)	(fs_ ## t ## _function)
-#endif
 
 	if (index >= device_desc.bNumConfigurations)
 		return -EINVAL;
@@ -1217,7 +1187,7 @@
 		if (number)
 			eth_reset_config (dev);
 		usb_gadget_vbus_draw(dev->gadget,
-				dev->gadget->is_otg ? 8 : 100);
+				gadget_is_otg(dev->gadget) ? 8 : 100);
 	} else {
 		char *speed;
 		unsigned power;
@@ -1399,24 +1369,22 @@
 			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)
+			if (!gadget_is_dualspeed(gadget))
 				break;
 			value = min (wLength, (u16) sizeof dev_qualifier);
 			memcpy (req->buf, &dev_qualifier, value);
 			break;
 
 		case USB_DT_OTHER_SPEED_CONFIG:
-			if (!gadget->is_dualspeed)
+			if (!gadget_is_dualspeed(gadget))
 				break;
 			// FALLTHROUGH
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
 		case USB_DT_CONFIG:
-			value = config_buf (gadget->speed, req->buf,
+			value = config_buf(gadget, req->buf,
 					wValue >> 8,
 					wValue & 0xff,
-					gadget->is_otg);
+					gadget_is_otg(gadget));
 			if (value >= 0)
 				value = min (wLength, (u16) value);
 			break;
@@ -1585,12 +1553,12 @@
 				&& rndis_control_intf.bInterfaceNumber
 					== wIndex) {
 			u8 *buf;
+			u32 n;
 
 			/* return the result */
-			buf = rndis_get_next_response (dev->rndis_config,
-						       &value);
+			buf = rndis_get_next_response(dev->rndis_config, &n);
 			if (buf) {
-				memcpy (req->buf, buf, value);
+				memcpy(req->buf, buf, n);
 				req->complete = rndis_response_complete;
 				rndis_free_response(dev->rndis_config, buf);
 			}
@@ -1989,8 +1957,20 @@
 	}
 
 	spin_lock_irqsave(&dev->req_lock, flags);
+	/*
+	 * this freelist can be empty if an interrupt triggered disconnect()
+	 * and reconfigured the gadget (shutting down this queue) after the
+	 * network stack decided to xmit but before we got the spinlock.
+	 */
+	if (list_empty(&dev->tx_reqs)) {
+		spin_unlock_irqrestore(&dev->req_lock, flags);
+		return 1;
+	}
+
 	req = container_of (dev->tx_reqs.next, struct usb_request, list);
 	list_del (&req->list);
+
+	/* temporarily stop TX queue when the freelist empties */
 	if (list_empty (&dev->tx_reqs))
 		netif_stop_queue (net);
 	spin_unlock_irqrestore(&dev->req_lock, flags);
@@ -2026,12 +2006,11 @@
 
 	req->length = length;
 
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
 	/* throttle highspeed IRQ rate back slightly */
-	req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)
-		? ((atomic_read (&dev->tx_qlen) % TX_DELAY) != 0)
-		: 0;
-#endif
+	if (gadget_is_dualspeed(dev->gadget))
+		req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)
+			? ((atomic_read(&dev->tx_qlen) % qmult) != 0)
+			: 0;
 
 	retval = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC);
 	switch (retval) {
@@ -2188,8 +2167,7 @@
 	}
 
 	if (rndis_active(dev)) {
-		rndis_set_param_medium (dev->rndis_config,
-					NDIS_MEDIUM_802_3, 0);
+		rndis_set_param_medium(dev->rndis_config, NDIS_MEDIUM_802_3, 0);
 		(void) rndis_signal_disconnect (dev->rndis_config);
 	}
 
@@ -2443,26 +2421,28 @@
 	if (rndis)
 		device_desc.bNumConfigurations = 2;
 
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
-	if (rndis)
-		dev_qualifier.bNumConfigurations = 2;
-	else if (!cdc)
-		dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC;
+	if (gadget_is_dualspeed(gadget)) {
+		if (rndis)
+			dev_qualifier.bNumConfigurations = 2;
+		else if (!cdc)
+			dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC;
 
-	/* assumes ep0 uses the same value for both speeds ... */
-	dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
+		/* assumes ep0 uses the same value for both speeds ... */
+		dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
 
-	/* and that all endpoints are dual-speed */
-	hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
-	hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
+		/* and that all endpoints are dual-speed */
+		hs_source_desc.bEndpointAddress =
+				fs_source_desc.bEndpointAddress;
+		hs_sink_desc.bEndpointAddress =
+				fs_sink_desc.bEndpointAddress;
 #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
-	if (status_ep)
-		hs_status_desc.bEndpointAddress =
-				fs_status_desc.bEndpointAddress;
+		if (status_ep)
+			hs_status_desc.bEndpointAddress =
+					fs_status_desc.bEndpointAddress;
 #endif
-#endif	/* DUALSPEED */
+	}
 
-	if (gadget->is_otg) {
+	if (gadget_is_otg(gadget)) {
 		otg_descriptor.bmAttributes |= USB_OTG_HNP,
 		eth_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
 		eth_config.bMaxPower = 4;
@@ -2598,12 +2578,11 @@
 		if (rndis_set_param_dev (dev->rndis_config, dev->net,
 					 &dev->stats, &dev->cdc_filter))
 			goto fail0;
-		if (rndis_set_param_vendor (dev->rndis_config, vendorID,
-					    manufacturer))
+		if (rndis_set_param_vendor(dev->rndis_config, vendorID,
+					manufacturer))
 			goto fail0;
-		if (rndis_set_param_medium (dev->rndis_config,
-					    NDIS_MEDIUM_802_3,
-					    0))
+		if (rndis_set_param_medium(dev->rndis_config,
+					NDIS_MEDIUM_802_3, 0))
 			goto fail0;
 		INFO (dev, "RNDIS ready\n");
 	}
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 965ad7b..73726c5 100644
--- 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-2005 Alan Stern
+ * Copyright (C) 2003-2007 Alan Stern
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -217,17 +217,11 @@
  */
 
 
-#undef DEBUG
-#undef VERBOSE
-#undef DUMP_MSGS
+/* #define VERBOSE_DEBUG */
+/* #define DUMP_MSGS */
 
 
-#include <asm/system.h>
-#include <asm/uaccess.h>
-
-#include <linux/bitops.h>
 #include <linux/blkdev.h>
-#include <linux/compiler.h>
 #include <linux/completion.h>
 #include <linux/dcache.h>
 #include <linux/delay.h>
@@ -235,18 +229,10 @@
 #include <linux/fcntl.h>
 #include <linux/file.h>
 #include <linux/fs.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
 #include <linux/kref.h>
 #include <linux/kthread.h>
 #include <linux/limits.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/pagemap.h>
 #include <linux/rwsem.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/string.h>
@@ -254,7 +240,7 @@
 #include <linux/utsname.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include "gadget_chips.h"
 
@@ -263,7 +249,7 @@
 
 #define DRIVER_DESC		"File-backed Storage Gadget"
 #define DRIVER_NAME		"g_file_storage"
-#define DRIVER_VERSION		"28 November 2005"
+#define DRIVER_VERSION		"7 August 2007"
 
 static const char longname[] = DRIVER_DESC;
 static const char shortname[] = DRIVER_NAME;
@@ -289,57 +275,48 @@
 
 /*-------------------------------------------------------------------------*/
 
-#define xprintk(f,level,fmt,args...) \
-	dev_printk(level , &(f)->gadget->dev , fmt , ## args)
-#define yprintk(l,level,fmt,args...) \
-	dev_printk(level , &(l)->dev , fmt , ## args)
-
 #ifdef DEBUG
-#define DBG(fsg,fmt,args...) \
-	xprintk(fsg , KERN_DEBUG , fmt , ## args)
 #define LDBG(lun,fmt,args...) \
-	yprintk(lun , KERN_DEBUG , fmt , ## args)
+	dev_dbg(&(lun)->dev , fmt , ## args)
 #define MDBG(fmt,args...) \
 	printk(KERN_DEBUG DRIVER_NAME ": " fmt , ## args)
 #else
-#define DBG(fsg,fmt,args...) \
-	do { } while (0)
 #define LDBG(lun,fmt,args...) \
 	do { } while (0)
 #define MDBG(fmt,args...) \
 	do { } while (0)
-#undef VERBOSE
+#undef VERBOSE_DEBUG
 #undef DUMP_MSGS
 #endif /* DEBUG */
 
-#ifdef VERBOSE
-#define VDBG	DBG
+#ifdef VERBOSE_DEBUG
 #define VLDBG	LDBG
 #else
-#define VDBG(fsg,fmt,args...) \
-	do { } while (0)
 #define VLDBG(lun,fmt,args...) \
 	do { } while (0)
-#endif /* VERBOSE */
+#endif /* VERBOSE_DEBUG */
 
-#define ERROR(fsg,fmt,args...) \
-	xprintk(fsg , KERN_ERR , fmt , ## args)
 #define LERROR(lun,fmt,args...) \
-	yprintk(lun , KERN_ERR , fmt , ## args)
-
-#define WARN(fsg,fmt,args...) \
-	xprintk(fsg , KERN_WARNING , fmt , ## args)
+	dev_err(&(lun)->dev , fmt , ## args)
 #define LWARN(lun,fmt,args...) \
-	yprintk(lun , KERN_WARNING , fmt , ## args)
-
-#define INFO(fsg,fmt,args...) \
-	xprintk(fsg , KERN_INFO , fmt , ## args)
+	dev_warn(&(lun)->dev , fmt , ## args)
 #define LINFO(lun,fmt,args...) \
-	yprintk(lun , KERN_INFO , fmt , ## args)
+	dev_info(&(lun)->dev , fmt , ## args)
 
 #define MINFO(fmt,args...) \
 	printk(KERN_INFO DRIVER_NAME ": " fmt , ## args)
 
+#define DBG(d, fmt, args...) \
+	dev_dbg(&(d)->gadget->dev , fmt , ## args)
+#define VDBG(d, fmt, args...) \
+	dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+#define ERROR(d, fmt, args...) \
+	dev_err(&(d)->gadget->dev , fmt , ## args)
+#define WARN(d, fmt, args...) \
+	dev_warn(&(d)->gadget->dev , fmt , ## args)
+#define INFO(d, fmt, args...) \
+	dev_info(&(d)->gadget->dev , fmt , ## args)
+
 
 /*-------------------------------------------------------------------------*/
 
@@ -350,8 +327,8 @@
 static struct {
 	char		*file[MAX_LUNS];
 	int		ro[MAX_LUNS];
-	int		num_filenames;
-	int		num_ros;
+	unsigned int	num_filenames;
+	unsigned int	num_ros;
 	unsigned int	nluns;
 
 	int		removable;
@@ -578,7 +555,7 @@
 
 #define backing_file_is_open(curlun)	((curlun)->filp != NULL)
 
-static inline struct lun *dev_to_lun(struct device *dev)
+static struct lun *dev_to_lun(struct device *dev)
 {
 	return container_of(dev, struct lun, dev);
 }
@@ -711,13 +688,13 @@
 
 typedef void (*fsg_routine_t)(struct fsg_dev *);
 
-static int inline exception_in_progress(struct fsg_dev *fsg)
+static int exception_in_progress(struct fsg_dev *fsg)
 {
 	return (fsg->state > FSG_STATE_IDLE);
 }
 
 /* Make bulk-out requests be divisible by the maxpacket size */
-static void inline set_bulk_out_req_length(struct fsg_dev *fsg,
+static void set_bulk_out_req_length(struct fsg_dev *fsg,
 		struct fsg_buffhd *bh, unsigned int length)
 {
 	unsigned int	rem;
@@ -743,50 +720,36 @@
 static void dump_msg(struct fsg_dev *fsg, const char *label,
 		const u8 *buf, unsigned int length)
 {
-	unsigned int	start, num, i;
-	char		line[52], *p;
-
-	if (length >= 512)
-		return;
-	DBG(fsg, "%s, length %u:\n", label, length);
-
-	start = 0;
-	while (length > 0) {
-		num = min(length, 16u);
-		p = line;
-		for (i = 0; i < num; ++i) {
-			if (i == 8)
-				*p++ = ' ';
-			sprintf(p, " %02x", buf[i]);
-			p += 3;
-		}
-		*p = 0;
-		printk(KERN_DEBUG "%6x: %s\n", start, line);
-		buf += num;
-		start += num;
-		length -= num;
+	if (length < 512) {
+		DBG(fsg, "%s, length %u:\n", label, length);
+		print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET,
+				16, 1, buf, length, 0);
 	}
 }
 
-static void inline dump_cdb(struct fsg_dev *fsg)
+static void dump_cdb(struct fsg_dev *fsg)
 {}
 
 #else
 
-static void inline dump_msg(struct fsg_dev *fsg, const char *label,
+static void dump_msg(struct fsg_dev *fsg, const char *label,
 		const u8 *buf, unsigned int length)
 {}
 
-static void inline dump_cdb(struct fsg_dev *fsg)
-{
-	int	i;
-	char	cmdbuf[3*MAX_COMMAND_SIZE + 1];
+#ifdef VERBOSE_DEBUG
 
-	for (i = 0; i < fsg->cmnd_size; ++i)
-		sprintf(cmdbuf + i*3, " %02x", fsg->cmnd[i]);
-	VDBG(fsg, "SCSI CDB: %s\n", cmdbuf);
+static void dump_cdb(struct fsg_dev *fsg)
+{
+	print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE,
+			16, 1, fsg->cmnd, fsg->cmnd_size, 0);
 }
 
+#else
+
+static void dump_cdb(struct fsg_dev *fsg)
+{}
+
+#endif /* VERBOSE_DEBUG */
 #endif /* DUMP_MSGS */
 
 
@@ -809,24 +772,24 @@
 
 /* Routines for unaligned data access */
 
-static u16 inline get_be16(u8 *buf)
+static u16 get_be16(u8 *buf)
 {
 	return ((u16) buf[0] << 8) | ((u16) buf[1]);
 }
 
-static u32 inline get_be32(u8 *buf)
+static u32 get_be32(u8 *buf)
 {
 	return ((u32) buf[0] << 24) | ((u32) buf[1] << 16) |
 			((u32) buf[2] << 8) | ((u32) buf[3]);
 }
 
-static void inline put_be16(u8 *buf, u16 val)
+static void put_be16(u8 *buf, u16 val)
 {
 	buf[0] = val >> 8;
 	buf[1] = val;
 }
 
-static void inline put_be32(u8 *buf, u32 val)
+static void put_be32(u8 *buf, u32 val)
 {
 	buf[0] = val >> 24;
 	buf[1] = val >> 16;
@@ -950,8 +913,6 @@
 #define FS_FUNCTION_PRE_EP_ENTRIES	2
 
 
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
-
 /*
  * USB 2.0 devices need to expose both high speed and full speed
  * descriptors, unless they only run at full speed.
@@ -1014,14 +975,14 @@
 #define HS_FUNCTION_PRE_EP_ENTRIES	2
 
 /* Maxpacket and other transfer characteristics vary by speed. */
-#define ep_desc(g,fs,hs)	(((g)->speed==USB_SPEED_HIGH) ? (hs) : (fs))
-
-#else
-
-/* If there's no high speed support, always use the full-speed descriptor. */
-#define ep_desc(g,fs,hs)	fs
-
-#endif	/* !CONFIG_USB_GADGET_DUALSPEED */
+static struct usb_endpoint_descriptor *
+ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
+		struct usb_endpoint_descriptor *hs)
+{
+	if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+		return hs;
+	return fs;
+}
 
 
 /* The CBI specification limits the serial string to 12 uppercase hexadecimal
@@ -1053,26 +1014,22 @@
 static int populate_config_buf(struct usb_gadget *gadget,
 		u8 *buf, u8 type, unsigned index)
 {
-#ifdef CONFIG_USB_GADGET_DUALSPEED
 	enum usb_device_speed			speed = gadget->speed;
-#endif
 	int					len;
 	const struct usb_descriptor_header	**function;
 
 	if (index > 0)
 		return -EINVAL;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	if (type == USB_DT_OTHER_SPEED_CONFIG)
+	if (gadget_is_dualspeed(gadget) && type == USB_DT_OTHER_SPEED_CONFIG)
 		speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed;
-	if (speed == USB_SPEED_HIGH)
+	if (gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH)
 		function = hs_function;
 	else
-#endif
 		function = fs_function;
 
 	/* for now, don't advertise srp-only devices */
-	if (!gadget->is_otg)
+	if (!gadget_is_otg(gadget))
 		function++;
 
 	len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function);
@@ -1394,10 +1351,9 @@
 			value = sizeof device_desc;
 			memcpy(req->buf, &device_desc, value);
 			break;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
 		case USB_DT_DEVICE_QUALIFIER:
 			VDBG(fsg, "get device qualifier\n");
-			if (!fsg->gadget->is_dualspeed)
+			if (!gadget_is_dualspeed(fsg->gadget))
 				break;
 			value = sizeof dev_qualifier;
 			memcpy(req->buf, &dev_qualifier, value);
@@ -1405,15 +1361,12 @@
 
 		case USB_DT_OTHER_SPEED_CONFIG:
 			VDBG(fsg, "get other-speed config descriptor\n");
-			if (!fsg->gadget->is_dualspeed)
+			if (!gadget_is_dualspeed(fsg->gadget))
 				break;
 			goto get_config;
-#endif
 		case USB_DT_CONFIG:
 			VDBG(fsg, "get configuration descriptor\n");
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-		get_config:
-#endif
+get_config:
 			value = populate_config_buf(fsg->gadget,
 					req->buf,
 					w_value >> 8,
@@ -1646,7 +1599,8 @@
 		/* Wait for the next buffer to become available */
 		bh = fsg->next_buffhd_to_fill;
 		while (bh->state != BUF_STATE_EMPTY) {
-			if ((rc = sleep_thread(fsg)) != 0)
+			rc = sleep_thread(fsg);
+			if (rc)
 				return rc;
 		}
 
@@ -1885,7 +1839,8 @@
 		}
 
 		/* Wait for something to happen */
-		if ((rc = sleep_thread(fsg)) != 0)
+		rc = sleep_thread(fsg);
+		if (rc)
 			return rc;
 	}
 
@@ -2369,7 +2324,8 @@
 
 		/* Wait for the next buffer to be free */
 		while (bh->state != BUF_STATE_EMPTY) {
-			if ((rc = sleep_thread(fsg)) != 0)
+			rc = sleep_thread(fsg);
+			if (rc)
 				return rc;
 		}
 
@@ -2429,7 +2385,8 @@
 		}
 
 		/* Otherwise wait for something to happen */
-		if ((rc = sleep_thread(fsg)) != 0)
+		rc = sleep_thread(fsg);
+		if (rc)
 			return rc;
 	}
 	return 0;
@@ -2551,7 +2508,8 @@
 	/* Wait for the next buffer to become available */
 	bh = fsg->next_buffhd_to_fill;
 	while (bh->state != BUF_STATE_EMPTY) {
-		if ((rc = sleep_thread(fsg)) != 0)
+		rc = sleep_thread(fsg);
+		if (rc)
 			return rc;
 	}
 
@@ -2771,9 +2729,10 @@
 	/* Wait for the next buffer to become available for data or status */
 	bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill;
 	while (bh->state != BUF_STATE_EMPTY) {
-		if ((rc = sleep_thread(fsg)) != 0)
+		rc = sleep_thread(fsg);
+		if (rc)
 			return rc;
-		}
+	}
 	fsg->phase_error = 0;
 	fsg->short_packet_received = 0;
 
@@ -3005,7 +2964,7 @@
 
 	/* Is the CBW meaningful? */
 	if (cbw->Lun >= MAX_LUNS || cbw->Flags & ~USB_BULK_IN_FLAG ||
-			cbw->Length < 6 || cbw->Length > MAX_COMMAND_SIZE) {
+			cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) {
 		DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, "
 				"cmdlen %u\n",
 				cbw->Lun, cbw->Flags, cbw->Length);
@@ -3045,9 +3004,10 @@
 		/* Wait for the next buffer to become available */
 		bh = fsg->next_buffhd_to_fill;
 		while (bh->state != BUF_STATE_EMPTY) {
-			if ((rc = sleep_thread(fsg)) != 0)
+			rc = sleep_thread(fsg);
+			if (rc)
 				return rc;
-			}
+		}
 
 		/* Queue a request to read a Bulk-only CBW */
 		set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN);
@@ -3061,9 +3021,10 @@
 
 		/* Wait for the CBW to arrive */
 		while (bh->state != BUF_STATE_FULL) {
-			if ((rc = sleep_thread(fsg)) != 0)
+			rc = sleep_thread(fsg);
+			if (rc)
 				return rc;
-			}
+		}
 		smp_rmb();
 		rc = received_cbw(fsg, bh);
 		bh->state = BUF_STATE_EMPTY;
@@ -3072,9 +3033,10 @@
 
 		/* Wait for the next command to arrive */
 		while (fsg->cbbuf_cmnd_size == 0) {
-			if ((rc = sleep_thread(fsg)) != 0)
+			rc = sleep_thread(fsg);
+			if (rc)
 				return rc;
-			}
+		}
 
 		/* Is the previous status interrupt request still busy?
 		 * The host is allowed to skip reading the status,
@@ -3595,7 +3557,8 @@
 	return sprintf(buf, "%d\n", curlun->ro);
 }
 
-static ssize_t show_file(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_file(struct device *dev, struct device_attribute *attr,
+		char *buf)
 {
 	struct lun	*curlun = dev_to_lun(dev);
 	struct fsg_dev	*fsg = dev_get_drvdata(dev);
@@ -3604,8 +3567,8 @@
 
 	down_read(&fsg->filesem);
 	if (backing_file_is_open(curlun)) {	// Get the complete pathname
-		p = d_path(curlun->filp->f_path.dentry, curlun->filp->f_path.mnt,
-				buf, PAGE_SIZE - 1);
+		p = d_path(curlun->filp->f_path.dentry,
+				curlun->filp->f_path.mnt, buf, PAGE_SIZE - 1);
 		if (IS_ERR(p))
 			rc = PTR_ERR(p);
 		else {
@@ -3623,7 +3586,8 @@
 }
 
 
-static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t store_ro(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
 {
 	ssize_t		rc = count;
 	struct lun	*curlun = dev_to_lun(dev);
@@ -3647,7 +3611,8 @@
 	return rc;
 }
 
-static ssize_t store_file(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t store_file(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
 {
 	struct lun	*curlun = dev_to_lun(dev);
 	struct fsg_dev	*fsg = dev_get_drvdata(dev);
@@ -3859,7 +3824,7 @@
 	/* Find out how many LUNs there should be */
 	i = mod_data.nluns;
 	if (i == 0)
-		i = max(mod_data.num_filenames, 1);
+		i = max(mod_data.num_filenames, 1u);
 	if (i > MAX_LUNS) {
 		ERROR(fsg, "invalid number of LUNs: %d\n", i);
 		rc = -EINVAL;
@@ -3944,22 +3909,24 @@
 	intf_desc.bInterfaceProtocol = mod_data.transport_type;
 	fs_function[i + FS_FUNCTION_PRE_EP_ENTRIES] = NULL;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL;
+	if (gadget_is_dualspeed(gadget)) {
+		hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL;
 
-	/* Assume ep0 uses the same maxpacket value for both speeds */
-	dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
+		/* Assume ep0 uses the same maxpacket value for both speeds */
+		dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
 
-	/* Assume that all endpoint addresses are the same for both speeds */
-	hs_bulk_in_desc.bEndpointAddress = fs_bulk_in_desc.bEndpointAddress;
-	hs_bulk_out_desc.bEndpointAddress = fs_bulk_out_desc.bEndpointAddress;
-	hs_intr_in_desc.bEndpointAddress = fs_intr_in_desc.bEndpointAddress;
-#endif
-
-	if (gadget->is_otg) {
-		otg_desc.bmAttributes |= USB_OTG_HNP;
+		/* Assume endpoint addresses are the same for both speeds */
+		hs_bulk_in_desc.bEndpointAddress =
+				fs_bulk_in_desc.bEndpointAddress;
+		hs_bulk_out_desc.bEndpointAddress =
+				fs_bulk_out_desc.bEndpointAddress;
+		hs_intr_in_desc.bEndpointAddress =
+				fs_intr_in_desc.bEndpointAddress;
 	}
 
+	if (gadget_is_otg(gadget))
+		otg_desc.bmAttributes |= USB_OTG_HNP;
+
 	rc = -ENOMEM;
 
 	/* Allocate the request and buffer for endpoint 0 */
diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_usb2_udc.c
index d57bcfb..9bb7f64 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.c
+++ b/drivers/usb/gadget/fsl_usb2_udc.c
@@ -35,7 +35,7 @@
 #include <linux/moduleparam.h>
 #include <linux/device.h>
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 #include <linux/usb/otg.h>
 #include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
@@ -1090,14 +1090,11 @@
  */
 static int fsl_vbus_draw(struct usb_gadget *gadget, unsigned mA)
 {
-#ifdef CONFIG_USB_OTG
 	struct fsl_udc *udc;
 
 	udc = container_of(gadget, struct fsl_udc, gadget);
-
 	if (udc->transceiver)
 		return otg_set_power(udc->transceiver, mA);
-#endif
 	return -ENOTSUPP;
 }
 
@@ -1120,7 +1117,7 @@
 	return 0;
 }
 
-/* defined in usb_gadget.h */
+/* defined in gadget.h */
 static struct usb_gadget_ops fsl_gadget_ops = {
 	.get_frame = fsl_get_frame,
 	.wakeup = fsl_wakeup,
@@ -1321,7 +1318,7 @@
 				| USB_TYPE_STANDARD)) {
 			/* Note: The driver has not include OTG support yet.
 			 * This will be set when OTG support is added */
-			if (!udc->gadget.is_otg)
+			if (!gadget_is_otg(udc->gadget))
 				break;
 			else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE)
 				udc->gadget.b_hnp_enable = 1;
@@ -1330,6 +1327,8 @@
 			else if (setup->bRequest ==
 					USB_DEVICE_A_ALT_HNP_SUPPORT)
 				udc->gadget.a_alt_hnp_support = 1;
+			else
+				break;
 			rc = 0;
 		} else
 			break;
@@ -1840,10 +1839,8 @@
 	if (!driver || driver != udc_controller->driver || !driver->unbind)
 		return -EINVAL;
 
-#ifdef CONFIG_USB_OTG
 	if (udc_controller->transceiver)
 		(void)otg_set_peripheral(udc_controller->transceiver, 0);
-#endif
 
 	/* stop DR, disable intr */
 	dr_controller_stop(udc_controller);
diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c
index 1c5aa49..0689189 100644
--- a/drivers/usb/gadget/gmidi.c
+++ b/drivers/usb/gadget/gmidi.c
@@ -18,17 +18,11 @@
  * http://www.usb.org/developers/devclass_docs/midi10.pdf
  */
 
-#define DEBUG 1
-// #define VERBOSE
+/* #define VERBOSE_DEBUG */
 
-#include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
 #include <linux/utsname.h>
 #include <linux/device.h>
-#include <linux/moduleparam.h>
 
 #include <sound/driver.h>
 #include <sound/core.h>
@@ -36,7 +30,7 @@
 #include <sound/rawmidi.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 #include <linux/usb/audio.h>
 #include <linux/usb/midi.h>
 
@@ -139,30 +133,16 @@
 static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req);
 
 
-#define xprintk(d,level,fmt,args...) \
-	dev_printk(level , &(d)->gadget->dev , fmt , ## args)
-
-#ifdef DEBUG
-#define DBG(dev,fmt,args...) \
-	xprintk(dev , KERN_DEBUG , fmt , ## args)
-#else
-#define DBG(dev,fmt,args...) \
-	do { } while (0)
-#endif /* DEBUG */
-
-#ifdef VERBOSE
-#define VDBG	DBG
-#else
-#define VDBG(dev,fmt,args...) \
-	do { } while (0)
-#endif /* VERBOSE */
-
-#define ERROR(dev,fmt,args...) \
-	xprintk(dev , KERN_ERR , fmt , ## args)
-#define WARN(dev,fmt,args...) \
-	xprintk(dev , KERN_WARNING , fmt , ## args)
-#define INFO(dev,fmt,args...) \
-	xprintk(dev , KERN_INFO , fmt , ## args)
+#define DBG(d, fmt, args...) \
+	dev_dbg(&(d)->gadget->dev , fmt , ## args)
+#define VDBG(d, fmt, args...) \
+	dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+#define ERROR(d, fmt, args...) \
+	dev_err(&(d)->gadget->dev , fmt , ## args)
+#define WARN(d, fmt, args...) \
+	dev_warn(&(d)->gadget->dev , fmt , ## args)
+#define INFO(d, fmt, args...) \
+	dev_info(&(d)->gadget->dev , fmt , ## args)
 
 
 static unsigned buflen = 256;
@@ -425,7 +405,7 @@
 	return len;
 }
 
-static struct usb_request* alloc_ep_req(struct usb_ep *ep, unsigned length)
+static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length)
 {
 	struct usb_request	*req;
 
@@ -455,7 +435,7 @@
  * Receives a chunk of MIDI data.
  */
 static void gmidi_read_data(struct usb_ep *ep, int cable,
-				   uint8_t* data, int length)
+				   uint8_t *data, int length)
 {
 	struct gmidi_device *dev = ep->driver_data;
 	/* cable is ignored, because for now we only have one. */
@@ -541,7 +521,7 @@
 {
 	int err = 0;
 	struct usb_request *req;
-	struct usb_ep* ep;
+	struct usb_ep *ep;
 	unsigned i;
 
 	err = usb_ep_enable(dev->in_ep, &bulk_in_desc);
@@ -628,7 +608,7 @@
 
 	if (gadget_is_sa1100(gadget) && dev->config) {
 		/* tx fifo is full, but we can't clear it...*/
-		INFO(dev, "can't change configurations\n");
+		ERROR(dev, "can't change configurations\n");
 		return -ESPIPE;
 	}
 	gmidi_reset_config(dev);
@@ -843,7 +823,7 @@
 static void /* __init_or_exit */ gmidi_unbind(struct usb_gadget *gadget)
 {
 	struct gmidi_device *dev = get_gadget_data(gadget);
-	struct snd_card* card;
+	struct snd_card *card;
 
 	DBG(dev, "unbind\n");
 
@@ -867,12 +847,12 @@
 	return 0;
 }
 
-static void gmidi_transmit_packet(struct usb_request* req, uint8_t p0,
+static void gmidi_transmit_packet(struct usb_request *req, uint8_t p0,
 					uint8_t p1, uint8_t p2, uint8_t p3)
 {
 	unsigned length = req->length;
+	u8 *buf = (u8 *)req->buf + length;
 
-	uint8_t* buf = (uint8_t*)req->buf + length;
 	buf[0] = p0;
 	buf[1] = p1;
 	buf[2] = p2;
@@ -883,8 +863,8 @@
 /*
  * Converts MIDI commands to USB MIDI packets.
  */
-static void gmidi_transmit_byte(struct usb_request* req,
-				struct gmidi_in_port* port, uint8_t b)
+static void gmidi_transmit_byte(struct usb_request *req,
+				struct gmidi_in_port *port, uint8_t b)
 {
 	uint8_t p0 = port->cable;
 
@@ -981,10 +961,10 @@
 	}
 }
 
-static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req)
+static void gmidi_transmit(struct gmidi_device *dev, struct usb_request *req)
 {
-	struct usb_ep* ep = dev->in_ep;
-	struct gmidi_in_port* port = &dev->in_port;
+	struct usb_ep *ep = dev->in_ep;
+	struct gmidi_in_port *port = &dev->in_port;
 
 	if (!ep) {
 		return;
@@ -1020,14 +1000,14 @@
 
 static void gmidi_in_tasklet(unsigned long data)
 {
-	struct gmidi_device* dev = (struct gmidi_device*)data;
+	struct gmidi_device *dev = (struct gmidi_device *)data;
 
 	gmidi_transmit(dev, NULL);
 }
 
 static int gmidi_in_open(struct snd_rawmidi_substream *substream)
 {
-	struct gmidi_device* dev = substream->rmidi->private_data;
+	struct gmidi_device *dev = substream->rmidi->private_data;
 
 	VDBG(dev, "gmidi_in_open\n");
 	dev->in_substream = substream;
@@ -1037,13 +1017,15 @@
 
 static int gmidi_in_close(struct snd_rawmidi_substream *substream)
 {
+	struct gmidi_device *dev = substream->rmidi->private_data;
+
 	VDBG(dev, "gmidi_in_close\n");
 	return 0;
 }
 
 static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up)
 {
-	struct gmidi_device* dev = substream->rmidi->private_data;
+	struct gmidi_device *dev = substream->rmidi->private_data;
 
 	VDBG(dev, "gmidi_in_trigger %d\n", up);
 	dev->in_port.active = up;
@@ -1054,7 +1036,7 @@
 
 static int gmidi_out_open(struct snd_rawmidi_substream *substream)
 {
-	struct gmidi_device* dev = substream->rmidi->private_data;
+	struct gmidi_device *dev = substream->rmidi->private_data;
 
 	VDBG(dev, "gmidi_out_open\n");
 	dev->out_substream = substream;
@@ -1063,13 +1045,15 @@
 
 static int gmidi_out_close(struct snd_rawmidi_substream *substream)
 {
+	struct gmidi_device *dev = substream->rmidi->private_data;
+
 	VDBG(dev, "gmidi_out_close\n");
 	return 0;
 }
 
 static void gmidi_out_trigger(struct snd_rawmidi_substream *substream, int up)
 {
-	struct gmidi_device* dev = substream->rmidi->private_data;
+	struct gmidi_device *dev = substream->rmidi->private_data;
 
 	VDBG(dev, "gmidi_out_trigger %d\n", up);
 	if (up) {
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index 349b816..2ec9d19 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -37,7 +37,7 @@
 #include <linux/proc_fs.h>
 #include <linux/device.h>
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index 173004f..47ef8bd 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -20,8 +20,7 @@
  */
 
 
-// #define	DEBUG			/* data to help fault diagnosis */
-// #define	VERBOSE		/* extra debug messages (success too) */
+/* #define VERBOSE_DEBUG */
 
 #include <linux/init.h>
 #include <linux/module.h>
@@ -38,7 +37,7 @@
 #include <linux/moduleparam.h>
 
 #include <linux/usb/gadgetfs.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 
 /*
@@ -253,7 +252,7 @@
 	do { } while (0)
 #endif /* DEBUG */
 
-#ifdef VERBOSE
+#ifdef VERBOSE_DEBUG
 #define VDEBUG	DBG
 #else
 #define VDEBUG(dev,fmt,args...) \
@@ -1010,11 +1009,12 @@
 			/* assume that was SET_CONFIGURATION */
 			if (dev->current_config) {
 				unsigned power;
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
-				if (dev->gadget->speed == USB_SPEED_HIGH)
+
+				if (gadget_is_dualspeed(dev->gadget)
+						&& (dev->gadget->speed
+							== USB_SPEED_HIGH))
 					power = dev->hs_config->bMaxPower;
 				else
-#endif
 					power = dev->config->bMaxPower;
 				usb_gadget_vbus_draw(dev->gadget, 2 * power);
 			}
@@ -1355,24 +1355,21 @@
 config_buf (struct dev_data *dev, u8 type, unsigned index)
 {
 	int		len;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	int		hs;
-#endif
+	int		hs = 0;
 
 	/* only one configuration */
 	if (index > 0)
 		return -EINVAL;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	hs = (dev->gadget->speed == USB_SPEED_HIGH);
-	if (type == USB_DT_OTHER_SPEED_CONFIG)
-		hs = !hs;
+	if (gadget_is_dualspeed(dev->gadget)) {
+		hs = (dev->gadget->speed == USB_SPEED_HIGH);
+		if (type == USB_DT_OTHER_SPEED_CONFIG)
+			hs = !hs;
+	}
 	if (hs) {
 		dev->req->buf = dev->hs_config;
 		len = le16_to_cpu(dev->hs_config->wTotalLength);
-	} else
-#endif
-	{
+	} else {
 		dev->req->buf = dev->config;
 		len = le16_to_cpu(dev->config->wTotalLength);
 	}
@@ -1393,13 +1390,13 @@
 	spin_lock (&dev->lock);
 	dev->setup_abort = 0;
 	if (dev->state == STATE_DEV_UNCONNECTED) {
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
-		if (gadget->speed == USB_SPEED_HIGH && dev->hs_config == NULL) {
+		if (gadget_is_dualspeed(gadget)
+				&& gadget->speed == USB_SPEED_HIGH
+				&& dev->hs_config == NULL) {
 			spin_unlock(&dev->lock);
 			ERROR (dev, "no high speed config??\n");
 			return -EINVAL;
 		}
-#endif	/* CONFIG_USB_GADGET_DUALSPEED */
 
 		dev->state = STATE_DEV_CONNECTED;
 		dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;
@@ -1469,13 +1466,12 @@
 			// user mode expected to disable endpoints
 		} else {
 			u8	config, power;
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
-			if (gadget->speed == USB_SPEED_HIGH) {
+
+			if (gadget_is_dualspeed(gadget)
+					&& gadget->speed == USB_SPEED_HIGH) {
 				config = dev->hs_config->bConfigurationValue;
 				power = dev->hs_config->bMaxPower;
-			} else
-#endif
-			{
+			} else {
 				config = dev->config->bConfigurationValue;
 				power = dev->config->bMaxPower;
 			}
diff --git a/drivers/usb/gadget/lh7a40x_udc.h b/drivers/usb/gadget/lh7a40x_udc.h
index b3fe197..1ecfd63 100644
--- a/drivers/usb/gadget/lh7a40x_udc.h
+++ b/drivers/usb/gadget/lh7a40x_udc.h
@@ -50,7 +50,7 @@
 #include <asm/hardware.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 /*
  * Memory map
diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c
index 4b27d12..ebc5536 100644
--- a/drivers/usb/gadget/m66592-udc.c
+++ b/drivers/usb/gadget/m66592-udc.c
@@ -27,7 +27,7 @@
 #include <linux/platform_device.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include "m66592-udc.h"
 
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index c3d364e..d5d473f 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -62,7 +62,7 @@
 #include <linux/moduleparam.h>
 #include <linux/device.h>
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index 9b0f092..87c4f50 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -38,7 +38,7 @@
 #include <linux/moduleparam.h>
 #include <linux/platform_device.h>
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 #include <linux/usb/otg.h>
 #include <linux/dma-mapping.h>
 #include <linux/clk.h>
@@ -1241,19 +1241,15 @@
 	udc->gadget.dev.parent->power.power_state = PMSG_ON;
 	udc->gadget.dev.power.power_state = PMSG_ON;
 	UDC_SYSCON1_REG |= UDC_PULLUP_EN;
-#ifndef CONFIG_USB_OTG
-	if (!cpu_is_omap15xx())
+	if (!gadget_is_otg(udc->gadget) && !cpu_is_omap15xx())
 		OTG_CTRL_REG |= OTG_BSESSVLD;
-#endif
 	UDC_IRQ_EN_REG = UDC_DS_CHG_IE;
 }
 
 static void pullup_disable(struct omap_udc *udc)
 {
-#ifndef CONFIG_USB_OTG
-	if (!cpu_is_omap15xx())
+	if (!gadget_is_otg(udc->gadget) && !cpu_is_omap15xx())
 		OTG_CTRL_REG &= ~OTG_BSESSVLD;
-#endif
 	UDC_IRQ_EN_REG = UDC_DS_CHG_IE;
 	UDC_SYSCON1_REG &= ~UDC_PULLUP_EN;
 }
@@ -1390,7 +1386,7 @@
 {
 	u16	devstat;
 
-	if (!udc->gadget.is_otg)
+	if (!gadget_is_otg(udc->gadget))
 		return;
 
 	if (OTG_CTRL_REG & OTG_ID)
diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
index 1407ad1..3e71508 100644
--- a/drivers/usb/gadget/pxa2xx_udc.c
+++ b/drivers/usb/gadget/pxa2xx_udc.c
@@ -54,7 +54,7 @@
 #include <asm/hardware.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/mach/udc_pxa2xx.h>
 
diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
index 0be80c6..e3e90f8 100644
--- a/drivers/usb/gadget/s3c2410_udc.c
+++ b/drivers/usb/gadget/s3c2410_udc.c
@@ -42,7 +42,7 @@
 #include <linux/seq_file.h>
 
 #include <linux/usb.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index ce4d2e0..f5738eb 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -17,34 +17,15 @@
  *
  */
 
-#include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
 #include <linux/utsname.h>
-#include <linux/wait.h>
-#include <linux/proc_fs.h>
 #include <linux/device.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
-#include <linux/mutex.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/unaligned.h>
-#include <asm/uaccess.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/cdc.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include "gadget_chips.h"
 
@@ -89,30 +70,29 @@
 #define GS_DEFAULT_PARITY		USB_CDC_NO_PARITY
 #define GS_DEFAULT_CHAR_FORMAT		USB_CDC_1_STOP_BITS
 
-/* select highspeed/fullspeed, hiding highspeed if not configured */
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-#define GS_SPEED_SELECT(is_hs,hs,fs) ((is_hs) ? (hs) : (fs))
-#else
-#define GS_SPEED_SELECT(is_hs,hs,fs) (fs)
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
+/* maxpacket and other transfer characteristics vary by speed. */
+static inline struct usb_endpoint_descriptor *
+choose_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
+		struct usb_endpoint_descriptor *fs)
+{
+	if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+		return hs;
+	return fs;
+}
+
 
 /* debug settings */
-#ifdef GS_DEBUG
+#ifdef DEBUG
 static int debug = 1;
+#else
+#define	debug 0
+#endif
 
 #define gs_debug(format, arg...) \
 	do { if (debug) printk(KERN_DEBUG format, ## arg); } while(0)
 #define gs_debug_level(level, format, arg...) \
 	do { if (debug>=level) printk(KERN_DEBUG format, ## arg); } while(0)
 
-#else
-
-#define gs_debug(format, arg...) \
-	do { } while(0)
-#define gs_debug_level(level, format, arg...) \
-	do { } while(0)
-
-#endif /* GS_DEBUG */
 
 /* Thanks to NetChip Technologies for donating this product ID.
  *
@@ -147,10 +127,10 @@
 
 /* the port structure holds info for each port, one for each minor number */
 struct gs_port {
-	struct gs_dev 		*port_dev;	/* pointer to device struct */
+	struct gs_dev		*port_dev;	/* pointer to device struct */
 	struct tty_struct	*port_tty;	/* pointer to tty struct */
 	spinlock_t		port_lock;
-	int 			port_num;
+	int			port_num;
 	int			port_open_count;
 	int			port_in_use;	/* open/close in progress */
 	wait_queue_head_t	port_write_wait;/* waiting to write */
@@ -188,7 +168,7 @@
 /* tty driver */
 static int gs_open(struct tty_struct *tty, struct file *file);
 static void gs_close(struct tty_struct *tty, struct file *file);
-static int gs_write(struct tty_struct *tty, 
+static int gs_write(struct tty_struct *tty,
 	const unsigned char *buf, int count);
 static void gs_put_char(struct tty_struct *tty, unsigned char ch);
 static void gs_flush_chars(struct tty_struct *tty);
@@ -222,7 +202,7 @@
 static void gs_disconnect(struct usb_gadget *gadget);
 static int gs_set_config(struct gs_dev *dev, unsigned config);
 static void gs_reset_config(struct gs_dev *dev);
-static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
+static int gs_build_config_buf(u8 *buf, struct usb_gadget *g,
 		u8 type, unsigned int index, int is_otg);
 
 static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len,
@@ -415,18 +395,18 @@
 };
 
 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_CALL_MANAGEMENT_TYPE,
-	.bmCapabilities = 	0,
-	.bDataInterface = 	1,	/* index of data interface */
+	.bLength =		sizeof(gs_call_mgmt_descriptor),
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_CALL_MANAGEMENT_TYPE,
+	.bmCapabilities =	0,
+	.bDataInterface =	1,	/* index of data interface */
 };
 
 static struct usb_cdc_acm_descriptor gs_acm_descriptor = {
-	.bLength =  		sizeof(gs_acm_descriptor),
-	.bDescriptorType = 	USB_DT_CS_INTERFACE,
-	.bDescriptorSubType = 	USB_CDC_ACM_TYPE,
-	.bmCapabilities = 	0,
+	.bLength =		sizeof(gs_acm_descriptor),
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_ACM_TYPE,
+	.bmCapabilities =	0,
 };
 
 static const struct usb_cdc_union_desc gs_union_desc = {
@@ -436,7 +416,7 @@
 	.bMasterInterface0 =	0,	/* index of control interface */
 	.bSlaveInterface0 =	1,	/* index of data interface */
 };
- 
+
 static struct usb_endpoint_descriptor gs_fullspeed_notify_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
@@ -482,7 +462,6 @@
 	NULL,
 };
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
 static struct usb_endpoint_descriptor gs_highspeed_notify_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
@@ -536,15 +515,13 @@
 	NULL,
 };
 
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
-
 
 /* Module */
 MODULE_DESCRIPTION(GS_LONG_NAME);
 MODULE_AUTHOR("Al Borchers");
 MODULE_LICENSE("GPL");
 
-#ifdef GS_DEBUG
+#ifdef DEBUG
 module_param(debug, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on");
 #endif
@@ -915,7 +892,8 @@
 		return;
 	}
 
-	gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p, %p, %p\n", port->port_num, tty, ch, __builtin_return_address(0), __builtin_return_address(1), __builtin_return_address(2));
+	gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p\n",
+		port->port_num, tty, ch, __builtin_return_address(0));
 
 	spin_lock_irqsave(&port->port_lock, flags);
 
@@ -1116,7 +1094,11 @@
 		len = gs_send_packet(dev, req->buf, ep->maxpacket);
 
 		if (len > 0) {
-gs_debug_level(3, "gs_send: len=%d, 0x%2.2x 0x%2.2x 0x%2.2x ...\n", len, *((unsigned char *)req->buf), *((unsigned char *)req->buf+1), *((unsigned char *)req->buf+2));
+			gs_debug_level(3, "gs_send: len=%d, 0x%2.2x "
+					"0x%2.2x 0x%2.2x ...\n", len,
+					*((unsigned char *)req->buf),
+					*((unsigned char *)req->buf+1),
+					*((unsigned char *)req->buf+2));
 			list_del(&req_entry->re_entry);
 			req->length = len;
 			spin_unlock_irqrestore(&dev->dev_lock, flags);
@@ -1269,7 +1251,7 @@
 
 	switch(req->status) {
 	case 0:
- 		/* normal completion */
+		/* normal completion */
 		gs_recv_packet(dev, req->buf, req->actual);
 requeue:
 		req->length = ep->maxpacket;
@@ -1406,23 +1388,24 @@
 		? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
 	gs_device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	gs_qualifier_desc.bDeviceClass = use_acm
-		? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
-	/* assume ep0 uses the same packet size for both speeds */
-	gs_qualifier_desc.bMaxPacketSize0 = gs_device_desc.bMaxPacketSize0;
-	/* assume endpoints are dual-speed */
-	gs_highspeed_notify_desc.bEndpointAddress =
-		gs_fullspeed_notify_desc.bEndpointAddress;
-	gs_highspeed_in_desc.bEndpointAddress =
-		gs_fullspeed_in_desc.bEndpointAddress;
-	gs_highspeed_out_desc.bEndpointAddress =
-		gs_fullspeed_out_desc.bEndpointAddress;
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
+	if (gadget_is_dualspeed(gadget)) {
+		gs_qualifier_desc.bDeviceClass = use_acm
+			? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
+		/* assume ep0 uses the same packet size for both speeds */
+		gs_qualifier_desc.bMaxPacketSize0 =
+			gs_device_desc.bMaxPacketSize0;
+		/* assume endpoints are dual-speed */
+		gs_highspeed_notify_desc.bEndpointAddress =
+			gs_fullspeed_notify_desc.bEndpointAddress;
+		gs_highspeed_in_desc.bEndpointAddress =
+			gs_fullspeed_in_desc.bEndpointAddress;
+		gs_highspeed_out_desc.bEndpointAddress =
+			gs_fullspeed_out_desc.bEndpointAddress;
+	}
 
 	usb_gadget_set_selfpowered(gadget);
 
-	if (gadget->is_otg) {
+	if (gadget_is_otg(gadget)) {
 		gs_otg_descriptor.bmAttributes |= USB_OTG_HNP,
 		gs_bulk_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
 		gs_acm_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
@@ -1487,6 +1470,12 @@
 			dev->dev_ctrl_req = NULL;
 		}
 		gs_free_ports(dev);
+		if (dev->dev_notify_ep)
+			usb_ep_disable(dev->dev_notify_ep);
+		if (dev->dev_in_ep)
+			usb_ep_disable(dev->dev_in_ep);
+		if (dev->dev_out_ep)
+			usb_ep_disable(dev->dev_out_ep);
 		kfree(dev);
 		set_gadget_data(gadget, NULL);
 	}
@@ -1570,9 +1559,8 @@
 			memcpy(req->buf, &gs_device_desc, ret);
 			break;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
 		case USB_DT_DEVICE_QUALIFIER:
-			if (!gadget->is_dualspeed)
+			if (!gadget_is_dualspeed(gadget))
 				break;
 			ret = min(wLength,
 				(u16)sizeof(struct usb_qualifier_descriptor));
@@ -1580,14 +1568,13 @@
 			break;
 
 		case USB_DT_OTHER_SPEED_CONFIG:
-			if (!gadget->is_dualspeed)
+			if (!gadget_is_dualspeed(gadget))
 				break;
 			/* fall through */
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
 		case USB_DT_CONFIG:
-			ret = gs_build_config_buf(req->buf, gadget->speed,
+			ret = gs_build_config_buf(req->buf, gadget,
 				wValue >> 8, wValue & 0xff,
-				gadget->is_otg);
+				gadget_is_otg(gadget));
 			if (ret >= 0)
 				ret = min(wLength, (u16)ret);
 			break;
@@ -1827,8 +1814,7 @@
 
 		if (EP_NOTIFY_NAME
 		&& strcmp(ep->name, EP_NOTIFY_NAME) == 0) {
-			ep_desc = GS_SPEED_SELECT(
-				gadget->speed == USB_SPEED_HIGH,
+			ep_desc = choose_ep_desc(gadget,
 				&gs_highspeed_notify_desc,
 				&gs_fullspeed_notify_desc);
 			ret = usb_ep_enable(ep,ep_desc);
@@ -1844,9 +1830,8 @@
 		}
 
 		else if (strcmp(ep->name, EP_IN_NAME) == 0) {
-			ep_desc = GS_SPEED_SELECT(
-				gadget->speed == USB_SPEED_HIGH,
- 				&gs_highspeed_in_desc,
+			ep_desc = choose_ep_desc(gadget,
+				&gs_highspeed_in_desc,
 				&gs_fullspeed_in_desc);
 			ret = usb_ep_enable(ep,ep_desc);
 			if (ret == 0) {
@@ -1861,8 +1846,7 @@
 		}
 
 		else if (strcmp(ep->name, EP_OUT_NAME) == 0) {
-			ep_desc = GS_SPEED_SELECT(
-				gadget->speed == USB_SPEED_HIGH,
+			ep_desc = choose_ep_desc(gadget,
 				&gs_highspeed_out_desc,
 				&gs_fullspeed_out_desc);
 			ret = usb_ep_enable(ep,ep_desc);
@@ -1981,11 +1965,11 @@
  * Builds the config descriptors in the given buffer and returns the
  * length, or a negative error number.
  */
-static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
+static int gs_build_config_buf(u8 *buf, struct usb_gadget *g,
 	u8 type, unsigned int index, int is_otg)
 {
 	int len;
-	int high_speed;
+	int high_speed = 0;
 	const struct usb_config_descriptor *config_desc;
 	const struct usb_descriptor_header **function;
 
@@ -1993,20 +1977,22 @@
 		return -EINVAL;
 
 	/* other speed switches high and full speed */
-	high_speed = (speed == USB_SPEED_HIGH);
-	if (type == USB_DT_OTHER_SPEED_CONFIG)
-		high_speed = !high_speed;
+	if (gadget_is_dualspeed(g)) {
+		high_speed = (g->speed == USB_SPEED_HIGH);
+		if (type == USB_DT_OTHER_SPEED_CONFIG)
+			high_speed = !high_speed;
+	}
 
 	if (use_acm) {
 		config_desc = &gs_acm_config_desc;
-		function = GS_SPEED_SELECT(high_speed,
-			gs_acm_highspeed_function,
-			gs_acm_fullspeed_function);
+		function = high_speed
+			? gs_acm_highspeed_function
+			: gs_acm_fullspeed_function;
 	} else {
 		config_desc = &gs_bulk_config_desc;
-		function = GS_SPEED_SELECT(high_speed,
-			gs_bulk_highspeed_function,
-			gs_bulk_fullspeed_function);
+		function = high_speed
+			? gs_bulk_highspeed_function
+			: gs_bulk_fullspeed_function;
 	}
 
 	/* for now, don't advertise srp-only devices */
diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c
index 3459ea6..878e428 100644
--- a/drivers/usb/gadget/usbstring.c
+++ b/drivers/usb/gadget/usbstring.c
@@ -15,7 +15,7 @@
 #include <linux/init.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/unaligned.h>
 
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index fcfe869..fcde5d9 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -1,38 +1,22 @@
 /*
  * zero.c -- Gadget Zero, for USB development
  *
- * Copyright (C) 2003-2004 David Brownell
+ * Copyright (C) 2003-2007 David Brownell
  * 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. 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 names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") as published by the Free Software
- * Foundation, either version 2 of that 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.
  *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 
@@ -57,40 +41,28 @@
  * Many drivers will only have one configuration, letting them be much
  * simpler if they also don't support high speed operation (like this
  * driver does).
+ *
+ * Why is *this* driver using two configurations, rather than setting up
+ * two interfaces with different functions?  To help verify that multiple
+ * configuration infrastucture is working correctly; also, so that it can
+ * work with low capability USB controllers without four bulk endpoints.
  */
 
-#define DEBUG 1
-// #define VERBOSE
+/* #define VERBOSE_DEBUG */
 
-#include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
 #include <linux/utsname.h>
 #include <linux/device.h>
-#include <linux/moduleparam.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/unaligned.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include "gadget_chips.h"
 
 
 /*-------------------------------------------------------------------------*/
 
-#define DRIVER_VERSION		"St Patrick's Day 2004"
+#define DRIVER_VERSION		"Lughnasadh, 2007"
 
 static const char shortname [] = "zero";
 static const char longname [] = "Gadget Zero";
@@ -131,30 +103,16 @@
 	struct timer_list	resume;
 };
 
-#define xprintk(d,level,fmt,args...) \
-	dev_printk(level , &(d)->gadget->dev , fmt , ## args)
-
-#ifdef DEBUG
-#define DBG(dev,fmt,args...) \
-	xprintk(dev , KERN_DEBUG , fmt , ## args)
-#else
-#define DBG(dev,fmt,args...) \
-	do { } while (0)
-#endif /* DEBUG */
-
-#ifdef VERBOSE
-#define VDBG	DBG
-#else
-#define VDBG(dev,fmt,args...) \
-	do { } while (0)
-#endif /* VERBOSE */
-
-#define ERROR(dev,fmt,args...) \
-	xprintk(dev , KERN_ERR , fmt , ## args)
-#define WARN(dev,fmt,args...) \
-	xprintk(dev , KERN_WARNING , fmt , ## args)
-#define INFO(dev,fmt,args...) \
-	xprintk(dev , KERN_INFO , fmt , ## args)
+#define DBG(d, fmt, args...) \
+	dev_dbg(&(d)->gadget->dev , fmt , ## args)
+#define VDBG(d, fmt, args...) \
+	dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+#define ERROR(d, fmt, args...) \
+	dev_err(&(d)->gadget->dev , fmt , ## args)
+#define WARN(d, fmt, args...) \
+	dev_warn(&(d)->gadget->dev , fmt , ## args)
+#define INFO(d, fmt, args...) \
+	dev_info(&(d)->gadget->dev , fmt , ## args)
 
 /*-------------------------------------------------------------------------*/
 
@@ -326,8 +284,6 @@
 	NULL,
 };
 
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
-
 /*
  * usb 2.0 devices need to expose both high speed and full speed
  * descriptors, unless they only run at full speed.
@@ -383,17 +339,20 @@
 };
 
 /* maxpacket and other transfer characteristics vary by speed. */
-#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
+static inline struct usb_endpoint_descriptor *
+ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
+		struct usb_endpoint_descriptor *fs)
+{
+	if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+		return hs;
+	return fs;
+}
 
-#else
+static char manufacturer[50];
 
-/* if there's no high speed support, maxpacket doesn't change. */
-#define ep_desc(g,hs,fs) fs
+/* default serial number takes at least two packets */
+static char serial[] = "0123456789.0123456789.0123456789";
 
-#endif	/* !CONFIG_USB_GADGET_DUALSPEED */
-
-static char				manufacturer [50];
-static char				serial [40];
 
 /* static strings, in UTF-8 */
 static struct usb_string		strings [] = {
@@ -435,30 +394,29 @@
 	int				is_source_sink;
 	int				len;
 	const struct usb_descriptor_header **function;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	int				hs = (gadget->speed == USB_SPEED_HIGH);
-#endif
+	int				hs = 0;
 
 	/* two configurations will always be index 0 and index 1 */
 	if (index > 1)
 		return -EINVAL;
 	is_source_sink = loopdefault ? (index == 1) : (index == 0);
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	if (type == USB_DT_OTHER_SPEED_CONFIG)
-		hs = !hs;
+	if (gadget_is_dualspeed(gadget)) {
+		hs = (gadget->speed == USB_SPEED_HIGH);
+		if (type == USB_DT_OTHER_SPEED_CONFIG)
+			hs = !hs;
+	}
 	if (hs)
 		function = is_source_sink
 			? hs_source_sink_function
 			: hs_loopback_function;
 	else
-#endif
 		function = is_source_sink
 			? fs_source_sink_function
 			: fs_loopback_function;
 
 	/* for now, don't advertise srp-only devices */
-	if (!gadget->is_otg)
+	if (!gadget_is_otg(gadget))
 		function++;
 
 	len = usb_gadget_config_buf (is_source_sink
@@ -498,6 +456,19 @@
 
 /*-------------------------------------------------------------------------*/
 
+/*
+ * SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripherals,
+ * this just sinks bulk packets OUT to the peripheral and sources them IN
+ * to the host, optionally with specific data patterns.
+ *
+ * In terms of control messaging, this supports all the standard requests
+ * plus two that support control-OUT tests.
+ *
+ * Note that because this doesn't queue more than one request at a time,
+ * some other function must be used to test queueing logic.  The network
+ * link (g_ether) is probably the best option for that.
+ */
+
 /* optionally require specific source/sink data patterns  */
 
 static int
@@ -534,12 +505,7 @@
 	return 0;
 }
 
-static void
-reinit_write_data (
-	struct zero_dev		*dev,
-	struct usb_ep		*ep,
-	struct usb_request	*req
-)
+static void reinit_write_data(struct usb_ep *ep, struct usb_request *req)
 {
 	unsigned	i;
 	u8		*buf = req->buf;
@@ -566,16 +532,16 @@
 
 	switch (status) {
 
-	case 0: 			/* normal completion? */
+	case 0:				/* normal completion? */
 		if (ep == dev->out_ep) {
 			check_read_data (dev, ep, req);
 			memset (req->buf, 0x55, req->length);
 		} else
-			reinit_write_data (dev, ep, req);
+			reinit_write_data(ep, req);
 		break;
 
 	/* this endpoint is normally active while we're configured */
-	case -ECONNABORTED: 		/* hardware forced ep reset */
+	case -ECONNABORTED:		/* hardware forced ep reset */
 	case -ECONNRESET:		/* request dequeued */
 	case -ESHUTDOWN:		/* disconnect from host */
 		VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status,
@@ -607,8 +573,7 @@
 	}
 }
 
-static struct usb_request *
-source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags)
+static struct usb_request *source_sink_start_ep(struct usb_ep *ep)
 {
 	struct usb_request	*req;
 	int			status;
@@ -621,11 +586,11 @@
 	req->complete = source_sink_complete;
 
 	if (strcmp (ep->name, EP_IN_NAME) == 0)
-		reinit_write_data (ep->driver_data, ep, req);
+		reinit_write_data(ep, req);
 	else
 		memset (req->buf, 0x55, req->length);
 
-	status = usb_ep_queue (ep, req, gfp_flags);
+	status = usb_ep_queue(ep, req, GFP_ATOMIC);
 	if (status) {
 		struct zero_dev	*dev = ep->driver_data;
 
@@ -637,8 +602,7 @@
 	return req;
 }
 
-static int
-set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags)
+static int set_source_sink_config(struct zero_dev *dev)
 {
 	int			result = 0;
 	struct usb_ep		*ep;
@@ -653,8 +617,7 @@
 			result = usb_ep_enable (ep, d);
 			if (result == 0) {
 				ep->driver_data = dev;
-				if (source_sink_start_ep(ep, gfp_flags)
-						!= NULL) {
+				if (source_sink_start_ep(ep) != NULL) {
 					dev->in_ep = ep;
 					continue;
 				}
@@ -668,8 +631,7 @@
 			result = usb_ep_enable (ep, d);
 			if (result == 0) {
 				ep->driver_data = dev;
-				if (source_sink_start_ep(ep, gfp_flags)
-						!= NULL) {
+				if (source_sink_start_ep(ep) != NULL) {
 					dev->out_ep = ep;
 					continue;
 				}
@@ -701,7 +663,7 @@
 
 	switch (status) {
 
-	case 0: 			/* normal completion? */
+	case 0:				/* normal completion? */
 		if (ep == dev->out_ep) {
 			/* loop this OUT packet back IN to the host */
 			req->zero = (req->actual < req->length);
@@ -735,7 +697,7 @@
 	 * rely on the hardware driver to clean up on disconnect or
 	 * endpoint disable.
 	 */
-	case -ECONNABORTED: 		/* hardware forced ep reset */
+	case -ECONNABORTED:		/* hardware forced ep reset */
 	case -ECONNRESET:		/* request dequeued */
 	case -ESHUTDOWN:		/* disconnect from host */
 		free_ep_req (ep, req);
@@ -743,8 +705,7 @@
 	}
 }
 
-static int
-set_loopback_config (struct zero_dev *dev, gfp_t gfp_flags)
+static int set_loopback_config(struct zero_dev *dev)
 {
 	int			result = 0;
 	struct usb_ep		*ep;
@@ -844,8 +805,7 @@
  * code can do, perhaps by disallowing more than one configuration or
  * by limiting configuration choices (like the pxa2xx).
  */
-static int
-zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags)
+static int zero_set_config(struct zero_dev *dev, unsigned number)
 {
 	int			result = 0;
 	struct usb_gadget	*gadget = dev->gadget;
@@ -855,17 +815,17 @@
 
 	if (gadget_is_sa1100 (gadget) && dev->config) {
 		/* tx fifo is full, but we can't clear it...*/
-		INFO (dev, "can't change configurations\n");
+		ERROR(dev, "can't change configurations\n");
 		return -ESPIPE;
 	}
 	zero_reset_config (dev);
 
 	switch (number) {
 	case CONFIG_SOURCE_SINK:
-		result = set_source_sink_config (dev, gfp_flags);
+		result = set_source_sink_config(dev);
 		break;
 	case CONFIG_LOOPBACK:
-		result = set_loopback_config (dev, gfp_flags);
+		result = set_loopback_config(dev);
 		break;
 	default:
 		result = -EINVAL;
@@ -885,7 +845,7 @@
 		case USB_SPEED_LOW:	speed = "low"; break;
 		case USB_SPEED_FULL:	speed = "full"; break;
 		case USB_SPEED_HIGH:	speed = "high"; break;
-		default: 		speed = "?"; break;
+		default:		speed = "?"; break;
 		}
 
 		dev->config = number;
@@ -938,19 +898,17 @@
 			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)
+			if (!gadget_is_dualspeed(gadget))
 				break;
 			value = min (w_length, (u16) sizeof dev_qualifier);
 			memcpy (req->buf, &dev_qualifier, value);
 			break;
 
 		case USB_DT_OTHER_SPEED_CONFIG:
-			if (!gadget->is_dualspeed)
+			if (!gadget_is_dualspeed(gadget))
 				break;
 			// FALLTHROUGH
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
 		case USB_DT_CONFIG:
 			value = config_buf (gadget, req->buf,
 					w_value >> 8,
@@ -984,7 +942,7 @@
 		else
 			VDBG (dev, "HNP inactive\n");
 		spin_lock (&dev->lock);
-		value = zero_set_config (dev, w_value, GFP_ATOMIC);
+		value = zero_set_config(dev, w_value);
 		spin_unlock (&dev->lock);
 		break;
 	case USB_REQ_GET_CONFIGURATION:
@@ -1013,7 +971,7 @@
 			 * use this "reset the config" shortcut.
 			 */
 			zero_reset_config (dev);
-			zero_set_config (dev, config, GFP_ATOMIC);
+			zero_set_config(dev, config);
 			value = 0;
 		}
 		spin_unlock (&dev->lock);
@@ -1163,7 +1121,7 @@
 	}
 	EP_IN_NAME = ep->name;
 	ep->driver_data = ep;	/* claim */
-	
+
 	ep = usb_ep_autoconfig (gadget, &fs_sink_desc);
 	if (!ep)
 		goto autoconf_fail;
@@ -1207,16 +1165,18 @@
 
 	device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	/* assume ep0 uses the same value for both speeds ... */
-	dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
+	if (gadget_is_dualspeed(gadget)) {
+		/* assume ep0 uses the same value for both speeds ... */
+		dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
 
-	/* and that all endpoints are dual-speed */
-	hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
-	hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
-#endif
+		/* and that all endpoints are dual-speed */
+		hs_source_desc.bEndpointAddress =
+				fs_source_desc.bEndpointAddress;
+		hs_sink_desc.bEndpointAddress =
+				fs_sink_desc.bEndpointAddress;
+	}
 
-	if (gadget->is_otg) {
+	if (gadget_is_otg(gadget)) {
 		otg_descriptor.bmAttributes |= USB_OTG_HNP,
 		source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
 		loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
@@ -1294,23 +1254,18 @@
 	.suspend	= zero_suspend,
 	.resume		= zero_resume,
 
-	.driver 	= {
+	.driver		= {
 		.name		= (char *) shortname,
 		.owner		= THIS_MODULE,
 	},
 };
 
-MODULE_AUTHOR ("David Brownell");
-MODULE_LICENSE ("Dual BSD/GPL");
+MODULE_AUTHOR("David Brownell");
+MODULE_LICENSE("GPL");
 
 
 static int __init init (void)
 {
-	/* a real value would likely come through some id prom
-	 * or module option.  this one takes at least two packets.
-	 */
-	strlcpy (serial, "0123456789.0123456789.0123456789", sizeof serial);
-
 	return usb_gadget_register_driver (&zero_driver);
 }
 module_init (init);
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 565d6ef..c978d62 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -154,6 +154,19 @@
 	  Enables support for PCI-bus plug-in USB controller cards.
 	  If unsure, say Y.
 
+config USB_OHCI_HCD_SSB
+	bool "OHCI support for Broadcom SSB OHCI core"
+	depends on USB_OHCI_HCD && SSB && EXPERIMENTAL
+	default n
+	---help---
+	  Support for the Sonics Silicon Backplane (SSB) attached
+	  Broadcom USB OHCI core.
+
+	  This device is present in some embedded devices with
+	  Broadcom based SSB bus.
+
+	  If unsure, say N.
+
 config USB_OHCI_BIG_ENDIAN_DESC
 	bool
 	depends on USB_OHCI_HCD
diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c
index b1d1926..766ef68 100644
--- a/drivers/usb/host/ehci-au1xxx.c
+++ b/drivers/usb/host/ehci-au1xxx.c
@@ -220,10 +220,8 @@
 	 */
 	.hub_status_data = ehci_hub_status_data,
 	.hub_control = ehci_hub_control,
-#ifdef	CONFIG_PM
-	.hub_suspend = ehci_hub_suspend,
-	.hub_resume = ehci_hub_resume,
-#endif
+	.bus_suspend = ehci_bus_suspend,
+	.bus_resume = ehci_bus_resume,
 };
 
 /*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 35cdba1..c151444 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -570,10 +570,18 @@
 	 * are explicitly handed to companion controller(s), so no TT is
 	 * involved with the root hub.  (Except where one is integrated,
 	 * and there's no companion controller unless maybe for USB OTG.)
+	 *
+	 * Turning on the CF flag will transfer ownership of all ports
+	 * from the companions to the EHCI controller.  If any of the
+	 * companions are in the middle of a port reset at the time, it
+	 * could cause trouble.  Write-locking ehci_cf_port_reset_rwsem
+	 * guarantees that no resets are in progress.
 	 */
+	down_write(&ehci_cf_port_reset_rwsem);
 	hcd->state = HC_STATE_RUNNING;
 	ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
 	ehci_readl(ehci, &ehci->regs->command);	/* unblock posted writes */
+	up_write(&ehci_cf_port_reset_rwsem);
 
 	temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
 	ehci_info (ehci,
@@ -719,7 +727,6 @@
  */
 static int ehci_urb_enqueue (
 	struct usb_hcd	*hcd,
-	struct usb_host_endpoint *ep,
 	struct urb	*urb,
 	gfp_t		mem_flags
 ) {
@@ -734,12 +741,12 @@
 	default:
 		if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
 			return -ENOMEM;
-		return submit_async (ehci, ep, urb, &qtd_list, mem_flags);
+		return submit_async(ehci, urb, &qtd_list, mem_flags);
 
 	case PIPE_INTERRUPT:
 		if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
 			return -ENOMEM;
-		return intr_submit (ehci, ep, urb, &qtd_list, mem_flags);
+		return intr_submit(ehci, urb, &qtd_list, mem_flags);
 
 	case PIPE_ISOCHRONOUS:
 		if (urb->dev->speed == USB_SPEED_HIGH)
@@ -777,13 +784,18 @@
  * completions normally happen asynchronously
  */
 
-static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
 	struct ehci_qh		*qh;
 	unsigned long		flags;
+	int			rc;
 
 	spin_lock_irqsave (&ehci->lock, flags);
+	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (rc)
+		goto done;
+
 	switch (usb_pipetype (urb->pipe)) {
 	// case PIPE_CONTROL:
 	// case PIPE_BULK:
@@ -838,7 +850,7 @@
 	}
 done:
 	spin_unlock_irqrestore (&ehci->lock, flags);
-	return 0;
+	return rc;
 }
 
 /*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index a7816e3..ad0d496 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -58,8 +58,6 @@
 	if (!retval)
 		ehci_dbg(ehci, "MWI active\n");
 
-	ehci_port_power(ehci, 0);
-
 	return 0;
 }
 
@@ -156,8 +154,7 @@
 		break;
 	}
 
-	if (ehci_is_TDI(ehci))
-		ehci_reset(ehci);
+	ehci_reset(ehci);
 
 	/* at least the Genesys GL880S needs fixup here */
 	temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params);
diff --git a/drivers/usb/host/ehci-ppc-soc.c b/drivers/usb/host/ehci-ppc-soc.c
index 4f99b0e..452d4b1 100644
--- a/drivers/usb/host/ehci-ppc-soc.c
+++ b/drivers/usb/host/ehci-ppc-soc.c
@@ -160,10 +160,8 @@
 	 */
 	.hub_status_data = ehci_hub_status_data,
 	.hub_control = ehci_hub_control,
-#ifdef	CONFIG_PM
-	.hub_suspend = ehci_hub_suspend,
-	.hub_resume = ehci_hub_resume,
-#endif
+	.bus_suspend = ehci_bus_suspend,
+	.bus_resume = ehci_bus_resume,
 };
 
 static int ehci_hcd_ppc_soc_drv_probe(struct platform_device *pdev)
diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c
index 829fe64..03a6b2f 100644
--- a/drivers/usb/host/ehci-ps3.c
+++ b/drivers/usb/host/ehci-ps3.c
@@ -47,7 +47,7 @@
 	if (result)
 		return result;
 
-	ehci_port_power(ehci, 0);
+	ehci_reset(ehci);
 
 	return result;
 }
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 140bfa4..b10f39c 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -139,63 +139,65 @@
 
 /*-------------------------------------------------------------------------*/
 
-static void qtd_copy_status (
+static int qtd_copy_status (
 	struct ehci_hcd *ehci,
 	struct urb *urb,
 	size_t length,
 	u32 token
 )
 {
+	int	status = -EINPROGRESS;
+
 	/* count IN/OUT bytes, not SETUP (even short packets) */
 	if (likely (QTD_PID (token) != 2))
 		urb->actual_length += length - QTD_LENGTH (token);
 
 	/* don't modify error codes */
-	if (unlikely (urb->status != -EINPROGRESS))
-		return;
+	if (unlikely(urb->unlinked))
+		return status;
 
 	/* force cleanup after short read; not always an error */
 	if (unlikely (IS_SHORT_READ (token)))
-		urb->status = -EREMOTEIO;
+		status = -EREMOTEIO;
 
 	/* serious "can't proceed" faults reported by the hardware */
 	if (token & QTD_STS_HALT) {
 		if (token & QTD_STS_BABBLE) {
 			/* FIXME "must" disable babbling device's port too */
-			urb->status = -EOVERFLOW;
+			status = -EOVERFLOW;
 		} else if (token & QTD_STS_MMF) {
 			/* fs/ls interrupt xfer missed the complete-split */
-			urb->status = -EPROTO;
+			status = -EPROTO;
 		} else if (token & QTD_STS_DBE) {
-			urb->status = (QTD_PID (token) == 1) /* IN ? */
+			status = (QTD_PID (token) == 1) /* IN ? */
 				? -ENOSR  /* hc couldn't read data */
 				: -ECOMM; /* hc couldn't write data */
 		} else if (token & QTD_STS_XACT) {
 			/* timeout, bad crc, wrong PID, etc; retried */
 			if (QTD_CERR (token))
-				urb->status = -EPIPE;
+				status = -EPIPE;
 			else {
 				ehci_dbg (ehci, "devpath %s ep%d%s 3strikes\n",
 					urb->dev->devpath,
 					usb_pipeendpoint (urb->pipe),
 					usb_pipein (urb->pipe) ? "in" : "out");
-				urb->status = -EPROTO;
+				status = -EPROTO;
 			}
 		/* CERR nonzero + no errors + halt --> stall */
 		} else if (QTD_CERR (token))
-			urb->status = -EPIPE;
+			status = -EPIPE;
 		else	/* unknown */
-			urb->status = -EPROTO;
+			status = -EPROTO;
 
 		ehci_vdbg (ehci,
 			"dev%d ep%d%s qtd token %08x --> status %d\n",
 			usb_pipedevice (urb->pipe),
 			usb_pipeendpoint (urb->pipe),
 			usb_pipein (urb->pipe) ? "in" : "out",
-			token, urb->status);
+			token, status);
 
 		/* if async CSPLIT failed, try cleaning out the TT buffer */
-		if (urb->status != -EPIPE
+		if (status != -EPIPE
 				&& urb->dev->tt && !usb_pipeint (urb->pipe)
 				&& ((token & QTD_STS_MMF) != 0
 					|| QTD_CERR(token) == 0)
@@ -212,10 +214,12 @@
 			usb_hub_tt_clear_buffer (urb->dev, urb->pipe);
 		}
 	}
+
+	return status;
 }
 
 static void
-ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb)
+ehci_urb_done(struct ehci_hcd *ehci, struct urb *urb, int status)
 __releases(ehci->lock)
 __acquires(ehci->lock)
 {
@@ -231,25 +235,13 @@
 		qh_put (qh);
 	}
 
-	spin_lock (&urb->lock);
-	urb->hcpriv = NULL;
-	switch (urb->status) {
-	case -EINPROGRESS:		/* success */
-		urb->status = 0;
-	default:			/* fault */
-		COUNT (ehci->stats.complete);
-		break;
-	case -EREMOTEIO:		/* fault or normal */
-		if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
-			urb->status = 0;
-		COUNT (ehci->stats.complete);
-		break;
-	case -ECONNRESET:		/* canceled */
-	case -ENOENT:
-		COUNT (ehci->stats.unlink);
-		break;
+	if (unlikely(urb->unlinked)) {
+		COUNT(ehci->stats.unlink);
+	} else {
+		if (likely(status == -EINPROGRESS))
+			status = 0;
+		COUNT(ehci->stats.complete);
 	}
-	spin_unlock (&urb->lock);
 
 #ifdef EHCI_URB_TRACE
 	ehci_dbg (ehci,
@@ -257,13 +249,14 @@
 		__FUNCTION__, urb->dev->devpath, urb,
 		usb_pipeendpoint (urb->pipe),
 		usb_pipein (urb->pipe) ? "in" : "out",
-		urb->status,
+		status,
 		urb->actual_length, urb->transfer_buffer_length);
 #endif
 
 	/* complete() can reenter this HCD */
+	usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
 	spin_unlock (&ehci->lock);
-	usb_hcd_giveback_urb (ehci_to_hcd(ehci), urb);
+	usb_hcd_giveback_urb(ehci_to_hcd(ehci), urb, status);
 	spin_lock (&ehci->lock);
 }
 
@@ -283,6 +276,7 @@
 {
 	struct ehci_qtd		*last = NULL, *end = qh->dummy;
 	struct list_head	*entry, *tmp;
+	int			last_status = -EINPROGRESS;
 	int			stopped;
 	unsigned		count = 0;
 	int			do_status = 0;
@@ -311,6 +305,7 @@
 		struct ehci_qtd	*qtd;
 		struct urb	*urb;
 		u32		token = 0;
+		int		qtd_status;
 
 		qtd = list_entry (entry, struct ehci_qtd, qtd_list);
 		urb = qtd->urb;
@@ -318,11 +313,12 @@
 		/* clean up any state from previous QTD ...*/
 		if (last) {
 			if (likely (last->urb != urb)) {
-				ehci_urb_done (ehci, last->urb);
+				ehci_urb_done(ehci, last->urb, last_status);
 				count++;
 			}
 			ehci_qtd_free (ehci, last);
 			last = NULL;
+			last_status = -EINPROGRESS;
 		}
 
 		/* ignore urbs submitted during completions we reported */
@@ -358,13 +354,14 @@
 			stopped = 1;
 
 			if (unlikely (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)))
-				urb->status = -ESHUTDOWN;
+				last_status = -ESHUTDOWN;
 
 			/* ignore active urbs unless some previous qtd
 			 * for the urb faulted (including short read) or
 			 * its urb was canceled.  we may patch qh or qtds.
 			 */
-			if (likely (urb->status == -EINPROGRESS))
+			if (likely(last_status == -EINPROGRESS &&
+					!urb->unlinked))
 				continue;
 
 			/* issue status after short control reads */
@@ -392,11 +389,14 @@
 		}
 
 		/* remove it from the queue */
-		spin_lock (&urb->lock);
-		qtd_copy_status (ehci, urb, qtd->length, token);
-		do_status = (urb->status == -EREMOTEIO)
-				&& usb_pipecontrol (urb->pipe);
-		spin_unlock (&urb->lock);
+		qtd_status = qtd_copy_status(ehci, urb, qtd->length, token);
+		if (unlikely(qtd_status == -EREMOTEIO)) {
+			do_status = (!urb->unlinked &&
+					usb_pipecontrol(urb->pipe));
+			qtd_status = 0;
+		}
+		if (likely(last_status == -EINPROGRESS))
+			last_status = qtd_status;
 
 		if (stopped && qtd->qtd_list.prev != &qh->qtd_list) {
 			last = list_entry (qtd->qtd_list.prev,
@@ -409,7 +409,7 @@
 
 	/* last urb's completion might still need calling */
 	if (likely (last != NULL)) {
-		ehci_urb_done (ehci, last->urb);
+		ehci_urb_done(ehci, last->urb, last_status);
 		count++;
 		ehci_qtd_free (ehci, last);
 	}
@@ -913,7 +913,6 @@
 static int
 submit_async (
 	struct ehci_hcd		*ehci,
-	struct usb_host_endpoint *ep,
 	struct urb		*urb,
 	struct list_head	*qtd_list,
 	gfp_t			mem_flags
@@ -922,10 +921,10 @@
 	int			epnum;
 	unsigned long		flags;
 	struct ehci_qh		*qh = NULL;
-	int			rc = 0;
+	int			rc;
 
 	qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
-	epnum = ep->desc.bEndpointAddress;
+	epnum = urb->ep->desc.bEndpointAddress;
 
 #ifdef EHCI_URB_TRACE
 	ehci_dbg (ehci,
@@ -933,7 +932,7 @@
 		__FUNCTION__, urb->dev->devpath, urb,
 		epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out",
 		urb->transfer_buffer_length,
-		qtd, ep->hcpriv);
+		qtd, urb->ep->hcpriv);
 #endif
 
 	spin_lock_irqsave (&ehci->lock, flags);
@@ -942,9 +941,13 @@
 		rc = -ESHUTDOWN;
 		goto done;
 	}
+	rc = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
+	if (unlikely(rc))
+		goto done;
 
-	qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv);
+	qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv);
 	if (unlikely(qh == NULL)) {
+		usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
 		rc = -ENOMEM;
 		goto done;
 	}
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index e682f23..80d99bc 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -797,7 +797,6 @@
 
 static int intr_submit (
 	struct ehci_hcd		*ehci,
-	struct usb_host_endpoint *ep,
 	struct urb		*urb,
 	struct list_head	*qtd_list,
 	gfp_t			mem_flags
@@ -805,23 +804,26 @@
 	unsigned		epnum;
 	unsigned long		flags;
 	struct ehci_qh		*qh;
-	int			status = 0;
+	int			status;
 	struct list_head	empty;
 
 	/* get endpoint and transfer/schedule data */
-	epnum = ep->desc.bEndpointAddress;
+	epnum = urb->ep->desc.bEndpointAddress;
 
 	spin_lock_irqsave (&ehci->lock, flags);
 
 	if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
 			&ehci_to_hcd(ehci)->flags))) {
 		status = -ESHUTDOWN;
-		goto done;
+		goto done_not_linked;
 	}
+	status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
+	if (unlikely(status))
+		goto done_not_linked;
 
 	/* get qh and force any scheduling errors */
 	INIT_LIST_HEAD (&empty);
-	qh = qh_append_tds (ehci, urb, &empty, epnum, &ep->hcpriv);
+	qh = qh_append_tds(ehci, urb, &empty, epnum, &urb->ep->hcpriv);
 	if (qh == NULL) {
 		status = -ENOMEM;
 		goto done;
@@ -832,13 +834,16 @@
 	}
 
 	/* then queue the urb's tds to the qh */
-	qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv);
+	qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv);
 	BUG_ON (qh == NULL);
 
 	/* ... update usbfs periodic stats */
 	ehci_to_hcd(ehci)->self.bandwidth_int_reqs++;
 
 done:
+	if (unlikely(status))
+		usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
+done_not_linked:
 	spin_unlock_irqrestore (&ehci->lock, flags);
 	if (status)
 		qtd_list_free (ehci, urb, qtd_list);
@@ -1622,7 +1627,7 @@
 
 	/* give urb back to the driver ... can be out-of-order */
 	dev = urb->dev;
-	ehci_urb_done (ehci, urb);
+	ehci_urb_done(ehci, urb, 0);
 	urb = NULL;
 
 	/* defer stopping schedule; completion can submit */
@@ -1686,12 +1691,19 @@
 	/* schedule ... need to lock */
 	spin_lock_irqsave (&ehci->lock, flags);
 	if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
-			       &ehci_to_hcd(ehci)->flags)))
+			       &ehci_to_hcd(ehci)->flags))) {
 		status = -ESHUTDOWN;
-	else
-		status = iso_stream_schedule (ehci, urb, stream);
+		goto done_not_linked;
+	}
+	status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
+	if (unlikely(status))
+		goto done_not_linked;
+	status = iso_stream_schedule(ehci, urb, stream);
 	if (likely (status == 0))
 		itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
+	else
+		usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
+done_not_linked:
 	spin_unlock_irqrestore (&ehci->lock, flags);
 
 done:
@@ -1988,7 +2000,7 @@
 
 	/* give urb back to the driver */
 	dev = urb->dev;
-	ehci_urb_done (ehci, urb);
+	ehci_urb_done(ehci, urb, 0);
 	urb = NULL;
 
 	/* defer stopping schedule; completion can submit */
@@ -2049,12 +2061,19 @@
 	/* schedule ... need to lock */
 	spin_lock_irqsave (&ehci->lock, flags);
 	if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
-			       &ehci_to_hcd(ehci)->flags)))
+			       &ehci_to_hcd(ehci)->flags))) {
 		status = -ESHUTDOWN;
-	else
-		status = iso_stream_schedule (ehci, urb, stream);
+		goto done_not_linked;
+	}
+	status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
+	if (unlikely(status))
+		goto done_not_linked;
+	status = iso_stream_schedule(ehci, urb, stream);
 	if (status == 0)
 		sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
+	else
+		usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
+done_not_linked:
 	spin_unlock_irqrestore (&ehci->lock, flags);
 
 done:
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index 5c851a3..c27417f 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -277,12 +277,11 @@
   processed urbs.
 */
 static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep,
-			   struct urb *urb)
+			   struct urb *urb, int status)
 __releases(isp116x->lock) __acquires(isp116x->lock)
 {
 	unsigned i;
 
-	urb->hcpriv = NULL;
 	ep->error_count = 0;
 
 	if (usb_pipecontrol(urb->pipe))
@@ -290,8 +289,9 @@
 
 	urb_dbg(urb, "Finish");
 
+	usb_hcd_unlink_urb_from_ep(isp116x_to_hcd(isp116x), urb);
 	spin_unlock(&isp116x->lock);
-	usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb);
+	usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb, status);
 	spin_lock(&isp116x->lock);
 
 	/* take idle endpoints out of the schedule */
@@ -445,12 +445,7 @@
 			if (PTD_GET_ACTIVE(ptd)
 			    || (cc != TD_CC_NOERROR && cc < 0x0E))
 				break;
-			if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
-					urb->actual_length <
-						urb->transfer_buffer_length)
-				status = -EREMOTEIO;
-			else
-				status = 0;
+			status = 0;
 			ep->nextpid = 0;
 			break;
 		default:
@@ -458,14 +453,8 @@
 		}
 
  done:
-		if (status != -EINPROGRESS) {
-			spin_lock(&urb->lock);
-			if (urb->status == -EINPROGRESS)
-				urb->status = status;
-			spin_unlock(&urb->lock);
-		}
-		if (urb->status != -EINPROGRESS)
-			finish_request(isp116x, ep, urb);
+		if (status != -EINPROGRESS || urb->unlinked)
+			finish_request(isp116x, ep, urb, status);
 	}
 }
 
@@ -673,7 +662,7 @@
 /*-----------------------------------------------------------------*/
 
 static int isp116x_urb_enqueue(struct usb_hcd *hcd,
-			       struct usb_host_endpoint *hep, struct urb *urb,
+			       struct urb *urb,
 			       gfp_t mem_flags)
 {
 	struct isp116x *isp116x = hcd_to_isp116x(hcd);
@@ -682,6 +671,7 @@
 	int is_out = !usb_pipein(pipe);
 	int type = usb_pipetype(pipe);
 	int epnum = usb_pipeendpoint(pipe);
+	struct usb_host_endpoint *hep = urb->ep;
 	struct isp116x_ep *ep = NULL;
 	unsigned long flags;
 	int i;
@@ -705,7 +695,12 @@
 	if (!HC_IS_RUNNING(hcd->state)) {
 		kfree(ep);
 		ret = -ENODEV;
-		goto fail;
+		goto fail_not_linked;
+	}
+	ret = usb_hcd_link_urb_to_ep(hcd, urb);
+	if (ret) {
+		kfree(ep);
+		goto fail_not_linked;
 	}
 
 	if (hep->hcpriv)
@@ -808,16 +803,13 @@
 		}
 	}
 
-	/* in case of unlink-during-submit */
-	if (urb->status != -EINPROGRESS) {
-		finish_request(isp116x, ep, urb);
-		ret = 0;
-		goto fail;
-	}
 	urb->hcpriv = hep;
 	start_atl_transfers(isp116x);
 
       fail:
+	if (ret)
+		usb_hcd_unlink_urb_from_ep(hcd, urb);
+      fail_not_linked:
 	spin_unlock_irqrestore(&isp116x->lock, flags);
 	return ret;
 }
@@ -825,20 +817,21 @@
 /*
    Dequeue URBs.
 */
-static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
+		int status)
 {
 	struct isp116x *isp116x = hcd_to_isp116x(hcd);
 	struct usb_host_endpoint *hep;
 	struct isp116x_ep *ep, *ep_act;
 	unsigned long flags;
+	int rc;
 
 	spin_lock_irqsave(&isp116x->lock, flags);
+	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (rc)
+		goto done;
+
 	hep = urb->hcpriv;
-	/* URB already unlinked (or never linked)? */
-	if (!hep) {
-		spin_unlock_irqrestore(&isp116x->lock, flags);
-		return 0;
-	}
 	ep = hep->hcpriv;
 	WARN_ON(hep != ep->hep);
 
@@ -855,10 +848,10 @@
 			}
 
 	if (urb)
-		finish_request(isp116x, ep, urb);
-
+		finish_request(isp116x, ep, urb, status);
+ done:
 	spin_unlock_irqrestore(&isp116x->lock, flags);
-	return 0;
+	return rc;
 }
 
 static void isp116x_endpoint_disable(struct usb_hcd *hcd,
diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
index f61c6cd..ebab5ce 100644
--- a/drivers/usb/host/ohci-dbg.c
+++ b/drivers/usb/host/ohci-dbg.c
@@ -24,7 +24,7 @@
  * small: 0) header + data packets 1) just header
  */
 static void __maybe_unused
-urb_print (struct urb * urb, char * str, int small)
+urb_print(struct urb * urb, char * str, int small, int status)
 {
 	unsigned int pipe= urb->pipe;
 
@@ -34,7 +34,7 @@
 	}
 
 #ifndef	OHCI_VERBOSE_DEBUG
-	if (urb->status != 0)
+	if (status != 0)
 #endif
 	dbg("%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d",
 		    str,
@@ -46,7 +46,7 @@
 		    urb->transfer_flags,
 		    urb->actual_length,
 		    urb->transfer_buffer_length,
-		    urb->status);
+		    status);
 
 #ifdef	OHCI_VERBOSE_DEBUG
 	if (!small) {
@@ -66,7 +66,7 @@
 						urb->transfer_buffer_length: urb->actual_length;
 			for (i = 0; i < 16 && i < len; i++)
 				printk (" %02x", ((__u8 *) urb->transfer_buffer) [i]);
-			printk ("%s stat:%d\n", i < len? "...": "", urb->status);
+			printk ("%s stat:%d\n", i < len? "...": "", status);
 		}
 	}
 #endif
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 6edf409..240c7f5 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -81,7 +81,6 @@
 static int ohci_init (struct ohci_hcd *ohci);
 static void ohci_stop (struct usb_hcd *hcd);
 static int ohci_restart (struct ohci_hcd *ohci);
-static void ohci_quirk_nec_worker (struct work_struct *work);
 
 #include "ohci-hub.c"
 #include "ohci-dbg.c"
@@ -118,7 +117,6 @@
  */
 static int ohci_urb_enqueue (
 	struct usb_hcd	*hcd,
-	struct usb_host_endpoint *ep,
 	struct urb	*urb,
 	gfp_t		mem_flags
 ) {
@@ -131,11 +129,11 @@
 	int		retval = 0;
 
 #ifdef OHCI_VERBOSE_DEBUG
-	urb_print (urb, "SUB", usb_pipein (pipe));
+	urb_print(urb, "SUB", usb_pipein(pipe), -EINPROGRESS);
 #endif
 
 	/* every endpoint has a ed, locate and maybe (re)initialize it */
-	if (! (ed = ed_get (ohci, ep, urb->dev, pipe, urb->interval)))
+	if (! (ed = ed_get (ohci, urb->ep, urb->dev, pipe, urb->interval)))
 		return -ENOMEM;
 
 	/* for the private part of the URB we need the number of TDs (size) */
@@ -200,22 +198,17 @@
 		retval = -ENODEV;
 		goto fail;
 	}
-
-	/* in case of unlink-during-submit */
-	spin_lock (&urb->lock);
-	if (urb->status != -EINPROGRESS) {
-		spin_unlock (&urb->lock);
-		urb->hcpriv = urb_priv;
-		finish_urb (ohci, urb);
-		retval = 0;
+	retval = usb_hcd_link_urb_to_ep(hcd, urb);
+	if (retval)
 		goto fail;
-	}
 
 	/* schedule the ed if needed */
 	if (ed->state == ED_IDLE) {
 		retval = ed_schedule (ohci, ed);
-		if (retval < 0)
-			goto fail0;
+		if (retval < 0) {
+			usb_hcd_unlink_urb_from_ep(hcd, urb);
+			goto fail;
+		}
 		if (ed->type == PIPE_ISOCHRONOUS) {
 			u16	frame = ohci_frame_no(ohci);
 
@@ -239,8 +232,6 @@
 	urb->hcpriv = urb_priv;
 	td_submit_urb (ohci, urb);
 
-fail0:
-	spin_unlock (&urb->lock);
 fail:
 	if (retval)
 		urb_free_priv (ohci, urb_priv);
@@ -249,22 +240,26 @@
 }
 
 /*
- * decouple the URB from the HC queues (TDs, urb_priv); it's
- * already marked using urb->status.  reporting is always done
+ * decouple the URB from the HC queues (TDs, urb_priv).
+ * reporting is always done
  * asynchronously, and we might be dealing with an urb that's
  * partially transferred, or an ED with other urbs being unlinked.
  */
-static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
 	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
 	unsigned long		flags;
+	int			rc;
 
 #ifdef OHCI_VERBOSE_DEBUG
-	urb_print (urb, "UNLINK", 1);
+	urb_print(urb, "UNLINK", 1, status);
 #endif
 
 	spin_lock_irqsave (&ohci->lock, flags);
-	if (HC_IS_RUNNING(hcd->state)) {
+	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (rc) {
+		;	/* Do nothing */
+	} else if (HC_IS_RUNNING(hcd->state)) {
 		urb_priv_t  *urb_priv;
 
 		/* Unless an IRQ completed the unlink while it was being
@@ -282,10 +277,10 @@
 		 * any more ... just clean up every urb's memory.
 		 */
 		if (urb->hcpriv)
-			finish_urb (ohci, urb);
+			finish_urb(ohci, urb, status);
 	}
 	spin_unlock_irqrestore (&ohci->lock, flags);
-	return 0;
+	return rc;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -314,6 +309,8 @@
 	if (!HC_IS_RUNNING (hcd->state)) {
 sanitize:
 		ed->state = ED_IDLE;
+		if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT)
+			ohci->eds_scheduled--;
 		finish_unlinks (ohci, 0);
 	}
 
@@ -321,7 +318,12 @@
 	case ED_UNLINK:		/* wait for hw to finish? */
 		/* major IRQ delivery trouble loses INTR_SF too... */
 		if (limit-- == 0) {
-			ohci_warn (ohci, "IRQ INTR_SF lossage\n");
+			ohci_warn(ohci, "ED unlink timeout\n");
+			if (quirk_zfmicro(ohci)) {
+				ohci_warn(ohci, "Attempting ZF TD recovery\n");
+				ohci->ed_to_check = ed;
+				ohci->zf_delay = 2;
+			}
 			goto sanitize;
 		}
 		spin_unlock_irqrestore (&ohci->lock, flags);
@@ -379,6 +381,93 @@
 	(void) ohci_readl (ohci, &ohci->regs->control);
 }
 
+static int check_ed(struct ohci_hcd *ohci, struct ed *ed)
+{
+	return (hc32_to_cpu(ohci, ed->hwINFO) & ED_IN) != 0
+		&& (hc32_to_cpu(ohci, ed->hwHeadP) & TD_MASK)
+			== (hc32_to_cpu(ohci, ed->hwTailP) & TD_MASK)
+		&& !list_empty(&ed->td_list);
+}
+
+/* ZF Micro watchdog timer callback. The ZF Micro chipset sometimes completes
+ * an interrupt TD but neglects to add it to the donelist.  On systems with
+ * this chipset, we need to periodically check the state of the queues to look
+ * for such "lost" TDs.
+ */
+static void unlink_watchdog_func(unsigned long _ohci)
+{
+	long		flags;
+	unsigned	max;
+	unsigned	seen_count = 0;
+	unsigned	i;
+	struct ed	**seen = NULL;
+	struct ohci_hcd	*ohci = (struct ohci_hcd *) _ohci;
+
+	spin_lock_irqsave(&ohci->lock, flags);
+	max = ohci->eds_scheduled;
+	if (!max)
+		goto done;
+
+	if (ohci->ed_to_check)
+		goto out;
+
+	seen = kcalloc(max, sizeof *seen, GFP_ATOMIC);
+	if (!seen)
+		goto out;
+
+	for (i = 0; i < NUM_INTS; i++) {
+		struct ed	*ed = ohci->periodic[i];
+
+		while (ed) {
+			unsigned	temp;
+
+			/* scan this branch of the periodic schedule tree */
+			for (temp = 0; temp < seen_count; temp++) {
+				if (seen[temp] == ed) {
+					/* we've checked it and what's after */
+					ed = NULL;
+					break;
+				}
+			}
+			if (!ed)
+				break;
+			seen[seen_count++] = ed;
+			if (!check_ed(ohci, ed)) {
+				ed = ed->ed_next;
+				continue;
+			}
+
+			/* HC's TD list is empty, but HCD sees at least one
+			 * TD that's not been sent through the donelist.
+			 */
+			ohci->ed_to_check = ed;
+			ohci->zf_delay = 2;
+
+			/* The HC may wait until the next frame to report the
+			 * TD as done through the donelist and INTR_WDH.  (We
+			 * just *assume* it's not a multi-TD interrupt URB;
+			 * those could defer the IRQ more than one frame, using
+			 * DI...)  Check again after the next INTR_SF.
+			 */
+			ohci_writel(ohci, OHCI_INTR_SF,
+					&ohci->regs->intrstatus);
+			ohci_writel(ohci, OHCI_INTR_SF,
+					&ohci->regs->intrenable);
+
+			/* flush those writes */
+			(void) ohci_readl(ohci, &ohci->regs->control);
+
+			goto out;
+		}
+	}
+out:
+	kfree(seen);
+	if (ohci->eds_scheduled)
+		mod_timer(&ohci->unlink_watchdog, round_jiffies_relative(HZ));
+done:
+	spin_unlock_irqrestore(&ohci->lock, flags);
+}
+
 /*-------------------------------------------------------------------------*
  * HC functions
  *-------------------------------------------------------------------------*/
@@ -616,6 +705,15 @@
 	mdelay ((temp >> 23) & 0x1fe);
 	hcd->state = HC_STATE_RUNNING;
 
+	if (quirk_zfmicro(ohci)) {
+		/* Create timer to watch for bad queue state on ZF Micro */
+		setup_timer(&ohci->unlink_watchdog, unlink_watchdog_func,
+				(unsigned long) ohci);
+
+		ohci->eds_scheduled = 0;
+		ohci->ed_to_check = NULL;
+	}
+
 	ohci_dump (ohci, 1);
 
 	return 0;
@@ -629,10 +727,11 @@
 {
 	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
 	struct ohci_regs __iomem *regs = ohci->regs;
- 	int			ints; 
+	int			ints;
 
 	/* we can eliminate a (slow) ohci_readl()
-	   if _only_ WDH caused this irq */
+	 * if _only_ WDH caused this irq
+	 */
 	if ((ohci->hcca->done_head != 0)
 			&& ! (hc32_to_cpup (ohci, &ohci->hcca->done_head)
 				& 0x01)) {
@@ -651,7 +750,7 @@
 
 	if (ints & OHCI_INTR_UE) {
 		// e.g. due to PCI Master/Target Abort
-		if (ohci->flags & OHCI_QUIRK_NEC) {
+		if (quirk_nec(ohci)) {
 			/* Workaround for a silicon bug in some NEC chips used
 			 * in Apple's PowerBooks. Adapted from Darwin code.
 			 */
@@ -713,6 +812,31 @@
 			ohci_writel (ohci, OHCI_INTR_WDH, &regs->intrenable);
 	}
 
+	if (quirk_zfmicro(ohci) && (ints & OHCI_INTR_SF)) {
+		spin_lock(&ohci->lock);
+		if (ohci->ed_to_check) {
+			struct ed *ed = ohci->ed_to_check;
+
+			if (check_ed(ohci, ed)) {
+				/* HC thinks the TD list is empty; HCD knows
+				 * at least one TD is outstanding
+				 */
+				if (--ohci->zf_delay == 0) {
+					struct td *td = list_entry(
+						ed->td_list.next,
+						struct td, td_list);
+					ohci_warn(ohci,
+						  "Reclaiming orphan TD %p\n",
+						  td);
+					takeback_td(ohci, td);
+					ohci->ed_to_check = NULL;
+				}
+			} else
+				ohci->ed_to_check = NULL;
+		}
+		spin_unlock(&ohci->lock);
+	}
+
 	/* could track INTR_SO to reduce available PCI/... bandwidth */
 
 	/* handle any pending URB/ED unlinks, leaving INTR_SF enabled
@@ -721,7 +845,9 @@
 	spin_lock (&ohci->lock);
 	if (ohci->ed_rm_list)
 		finish_unlinks (ohci, ohci_frame_no(ohci));
-	if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list
+	if ((ints & OHCI_INTR_SF) != 0
+			&& !ohci->ed_rm_list
+			&& !ohci->ed_to_check
 			&& HC_IS_RUNNING(hcd->state))
 		ohci_writel (ohci, OHCI_INTR_SF, &regs->intrdisable);
 	spin_unlock (&ohci->lock);
@@ -751,6 +877,9 @@
 	free_irq(hcd->irq, hcd);
 	hcd->irq = -1;
 
+	if (quirk_zfmicro(ohci))
+		del_timer(&ohci->unlink_watchdog);
+
 	remove_debug_files (ohci);
 	ohci_mem_cleanup (ohci);
 	if (ohci->hcca) {
@@ -798,9 +927,8 @@
 					ed, ed->state);
 		}
 
-		spin_lock (&urb->lock);
-		urb->status = -ESHUTDOWN;
-		spin_unlock (&urb->lock);
+		if (!urb->unlinked)
+			urb->unlinked = -ESHUTDOWN;
 	}
 	finish_unlinks (ohci, 0);
 	spin_unlock_irq(&ohci->lock);
@@ -828,27 +956,6 @@
 
 /*-------------------------------------------------------------------------*/
 
-/* NEC workaround */
-static void ohci_quirk_nec_worker(struct work_struct *work)
-{
-	struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work);
-	int status;
-
-	status = ohci_init(ohci);
-	if (status != 0) {
-		ohci_err(ohci, "Restarting NEC controller failed "
-			 "in ohci_init, %d\n", status);
-		return;
-	}
-
-	status = ohci_restart(ohci);
-	if (status != 0)
-		ohci_err(ohci, "Restarting NEC controller failed "
-			 "in ohci_restart, %d\n", status);
-}
-
-/*-------------------------------------------------------------------------*/
-
 #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
 
 MODULE_AUTHOR (DRIVER_AUTHOR);
@@ -926,11 +1033,17 @@
 #define PS3_SYSTEM_BUS_DRIVER	ps3_ohci_driver
 #endif
 
+#ifdef CONFIG_USB_OHCI_HCD_SSB
+#include "ohci-ssb.c"
+#define SSB_OHCI_DRIVER		ssb_ohci_driver
+#endif
+
 #if	!defined(PCI_DRIVER) &&		\
 	!defined(PLATFORM_DRIVER) &&	\
 	!defined(OF_PLATFORM_DRIVER) &&	\
 	!defined(SA1111_DRIVER) &&	\
-	!defined(PS3_SYSTEM_BUS_DRIVER)
+	!defined(PS3_SYSTEM_BUS_DRIVER) && \
+	!defined(SSB_OHCI_DRIVER)
 #error "missing bus glue for ohci-hcd"
 #endif
 
@@ -975,10 +1088,20 @@
 		goto error_pci;
 #endif
 
+#ifdef SSB_OHCI_DRIVER
+	retval = ssb_driver_register(&SSB_OHCI_DRIVER);
+	if (retval)
+		goto error_ssb;
+#endif
+
 	return retval;
 
 	/* Error path */
+#ifdef SSB_OHCI_DRIVER
+ error_ssb:
+#endif
 #ifdef PCI_DRIVER
+	pci_unregister_driver(&PCI_DRIVER);
  error_pci:
 #endif
 #ifdef SA1111_DRIVER
@@ -1003,6 +1126,9 @@
 
 static void __exit ohci_hcd_mod_exit(void)
 {
+#ifdef SSB_OHCI_DRIVER
+	ssb_driver_unregister(&SSB_OHCI_DRIVER);
+#endif
 #ifdef PCI_DRIVER
 	pci_unregister_driver(&PCI_DRIVER);
 #endif
diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c
index 450c7b4..2f20d3d 100644
--- a/drivers/usb/host/ohci-mem.c
+++ b/drivers/usb/host/ohci-mem.c
@@ -28,7 +28,6 @@
 	ohci->next_statechange = jiffies;
 	spin_lock_init (&ohci->lock);
 	INIT_LIST_HEAD (&ohci->pending);
-	INIT_WORK (&ohci->nec_work, ohci_quirk_nec_worker);
 }
 
 /*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index a5e2eb8..d0360f6 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -84,7 +84,7 @@
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
 
 	ohci->flags |= OHCI_QUIRK_ZFMICRO;
-	ohci_dbg (ohci, "enabled Compaq ZFMicro chipset quirk\n");
+	ohci_dbg(ohci, "enabled Compaq ZFMicro chipset quirks\n");
 
 	return 0;
 }
@@ -113,11 +113,31 @@
 
 /* Check for NEC chip and apply quirk for allegedly lost interrupts.
  */
+
+static void ohci_quirk_nec_worker(struct work_struct *work)
+{
+	struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work);
+	int status;
+
+	status = ohci_init(ohci);
+	if (status != 0) {
+		ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n",
+			 "ohci_init", status);
+		return;
+	}
+
+	status = ohci_restart(ohci);
+	if (status != 0)
+		ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n",
+			 "ohci_restart", status);
+}
+
 static int ohci_quirk_nec(struct usb_hcd *hcd)
 {
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
 
 	ohci->flags |= OHCI_QUIRK_NEC;
+	INIT_WORK(&ohci->nec_work, ohci_quirk_nec_worker);
 	ohci_dbg (ohci, "enabled NEC chipset lost interrupt quirk\n");
 
 	return 0;
diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
index c43b66a..0a74269 100644
--- a/drivers/usb/host/ohci-ppc-of.c
+++ b/drivers/usb/host/ohci-ppc-of.c
@@ -134,8 +134,11 @@
 	}
 
 	ohci = hcd_to_ohci(hcd);
-	if (is_bigendian)
+	if (is_bigendian) {
 		ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
+		if (of_device_is_compatible(dn, "mpc5200-ohci"))
+			ohci->flags |= OHCI_QUIRK_FRAME_NO;
+	}
 
 	ohci_hcd_init(ohci);
 
diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c
index 1a2e177..f95be189 100644
--- a/drivers/usb/host/ohci-ppc-soc.c
+++ b/drivers/usb/host/ohci-ppc-soc.c
@@ -73,6 +73,11 @@
 
 	ohci = hcd_to_ohci(hcd);
 	ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
+
+#ifdef CONFIG_PPC_MPC52xx
+	/* MPC52xx doesn't need frame_no shift */
+	ohci->flags |= OHCI_QUIRK_FRAME_NO;
+#endif
 	ohci_hcd_init(ohci);
 
 	retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
index 830a3fe..5181732 100644
--- a/drivers/usb/host/ohci-q.c
+++ b/drivers/usb/host/ohci-q.c
@@ -36,29 +36,15 @@
  * PRECONDITION:  ohci lock held, irqs blocked.
  */
 static void
-finish_urb (struct ohci_hcd *ohci, struct urb *urb)
+finish_urb(struct ohci_hcd *ohci, struct urb *urb, int status)
 __releases(ohci->lock)
 __acquires(ohci->lock)
 {
 	// ASSERT (urb->hcpriv != 0);
 
 	urb_free_priv (ohci, urb->hcpriv);
-	urb->hcpriv = NULL;
-
-	spin_lock (&urb->lock);
-	if (likely (urb->status == -EINPROGRESS))
-		urb->status = 0;
-	/* report short control reads right even though the data TD always
-	 * has TD_R set.  (much simpler, but creates the 1-td limit.)
-	 */
-	if (unlikely (urb->transfer_flags & URB_SHORT_NOT_OK)
-			&& unlikely (usb_pipecontrol (urb->pipe))
-			&& urb->actual_length < urb->transfer_buffer_length
-			&& usb_pipein (urb->pipe)
-			&& urb->status == 0) {
-		urb->status = -EREMOTEIO;
-	}
-	spin_unlock (&urb->lock);
+	if (likely(status == -EINPROGRESS))
+		status = 0;
 
 	switch (usb_pipetype (urb->pipe)) {
 	case PIPE_ISOCHRONOUS:
@@ -70,12 +56,13 @@
 	}
 
 #ifdef OHCI_VERBOSE_DEBUG
-	urb_print (urb, "RET", usb_pipeout (urb->pipe));
+	urb_print(urb, "RET", usb_pipeout (urb->pipe), status);
 #endif
 
 	/* urb->complete() can reenter this HCD */
+	usb_hcd_unlink_urb_from_ep(ohci_to_hcd(ohci), urb);
 	spin_unlock (&ohci->lock);
-	usb_hcd_giveback_urb (ohci_to_hcd(ohci), urb);
+	usb_hcd_giveback_urb(ohci_to_hcd(ohci), urb, status);
 	spin_lock (&ohci->lock);
 
 	/* stop periodic dma if it's not needed */
@@ -179,6 +166,10 @@
 	ed->ed_prev = NULL;
 	ed->ed_next = NULL;
 	ed->hwNextED = 0;
+	if (quirk_zfmicro(ohci)
+			&& (ed->type == PIPE_INTERRUPT)
+			&& !(ohci->eds_scheduled++))
+		mod_timer(&ohci->unlink_watchdog, round_jiffies_relative(HZ));
 	wmb ();
 
 	/* we care about rm_list when setting CLE/BLE in case the HC was at
@@ -708,19 +699,18 @@
  * Done List handling functions
  *-------------------------------------------------------------------------*/
 
-/* calculate transfer length/status and update the urb
- * PRECONDITION:  irqsafe (only for urb->status locking)
- */
-static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
+/* calculate transfer length/status and update the urb */
+static int td_done(struct ohci_hcd *ohci, struct urb *urb, struct td *td)
 {
 	u32	tdINFO = hc32_to_cpup (ohci, &td->hwINFO);
 	int	cc = 0;
+	int	status = -EINPROGRESS;
 
 	list_del (&td->td_list);
 
 	/* ISO ... drivers see per-TD length/status */
 	if (tdINFO & TD_ISO) {
-		u16	tdPSW = ohci_hwPSW (ohci, td, 0);
+		u16	tdPSW = ohci_hwPSW(ohci, td, 0);
 		int	dlen = 0;
 
 		/* NOTE:  assumes FC in tdINFO == 0, and that
@@ -729,7 +719,7 @@
 
 		cc = (tdPSW >> 12) & 0xF;
 		if (tdINFO & TD_CC)	/* hc didn't touch? */
-			return;
+			return status;
 
 		if (usb_pipeout (urb->pipe))
 			dlen = urb->iso_frame_desc [td->index].length;
@@ -762,12 +752,8 @@
 		if (cc == TD_DATAUNDERRUN
 				&& !(urb->transfer_flags & URB_SHORT_NOT_OK))
 			cc = TD_CC_NOERROR;
-		if (cc != TD_CC_NOERROR && cc < 0x0E) {
-			spin_lock (&urb->lock);
-			if (urb->status == -EINPROGRESS)
-				urb->status = cc_to_error [cc];
-			spin_unlock (&urb->lock);
-		}
+		if (cc != TD_CC_NOERROR && cc < 0x0E)
+			status = cc_to_error[cc];
 
 		/* count all non-empty packets except control SETUP packet */
 		if ((type != PIPE_CONTROL || td->index != 0) && tdBE != 0) {
@@ -786,14 +772,15 @@
 				urb->actual_length,
 				urb->transfer_buffer_length);
 	}
+	return status;
 }
 
 /*-------------------------------------------------------------------------*/
 
-static inline struct td *
-ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
+static void ed_halted(struct ohci_hcd *ohci, struct td *td, int cc)
 {
 	struct urb		*urb = td->urb;
+	urb_priv_t		*urb_priv = urb->hcpriv;
 	struct ed		*ed = td->ed;
 	struct list_head	*tmp = td->td_list.next;
 	__hc32			toggle = ed->hwHeadP & cpu_to_hc32 (ohci, ED_C);
@@ -805,13 +792,12 @@
 	wmb ();
 	ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_H);
 
-	/* put any later tds from this urb onto the donelist, after 'td',
-	 * order won't matter here: no errors, and nothing was transferred.
-	 * also patch the ed so it looks as if those tds completed normally.
+	/* Get rid of all later tds from this urb.  We don't have
+	 * to be careful: no errors and nothing was transferred.
+	 * Also patch the ed so it looks as if those tds completed normally.
 	 */
 	while (tmp != &ed->td_list) {
 		struct td	*next;
-		__hc32		info;
 
 		next = list_entry (tmp, struct td, td_list);
 		tmp = next->td_list.next;
@@ -826,14 +812,9 @@
 		 * then we need to leave the control STATUS packet queued
 		 * and clear ED_SKIP.
 		 */
-		info = next->hwINFO;
-		info |= cpu_to_hc32 (ohci, TD_DONE);
-		info &= ~cpu_to_hc32 (ohci, TD_CC);
-		next->hwINFO = info;
 
-		next->next_dl_td = rev;
-		rev = next;
-
+		list_del(&next->td_list);
+		urb_priv->td_cnt++;
 		ed->hwHeadP = next->hwNextTD | toggle;
 	}
 
@@ -859,8 +840,6 @@
 			hc32_to_cpu (ohci, td->hwINFO),
 			cc, cc_to_error [cc]);
 	}
-
-	return rev;
 }
 
 /* replies to the request have to be on a FIFO basis so
@@ -897,7 +876,7 @@
 		 */
 		if (cc != TD_CC_NOERROR
 				&& (td->ed->hwHeadP & cpu_to_hc32 (ohci, ED_H)))
-			td_rev = ed_halted (ohci, td, cc, td_rev);
+			ed_halted(ohci, td, cc);
 
 		td->next_dl_td = td_rev;
 		td_rev = td;
@@ -940,8 +919,12 @@
 								TD_MASK;
 
 				/* INTR_WDH may need to clean up first */
-				if (td->td_dma != head)
-					goto skip_ed;
+				if (td->td_dma != head) {
+					if (ed == ohci->ed_to_check)
+						ohci->ed_to_check = NULL;
+					else
+						goto skip_ed;
+				}
 			}
 		}
 
@@ -974,7 +957,7 @@
 			urb = td->urb;
 			urb_priv = td->urb->hcpriv;
 
-			if (urb->status == -EINPROGRESS) {
+			if (!urb->unlinked) {
 				prev = &td->hwNextTD;
 				continue;
 			}
@@ -990,7 +973,7 @@
 			/* if URB is done, clean up */
 			if (urb_priv->td_cnt == urb_priv->length) {
 				modified = completed = 1;
-				finish_urb (ohci, urb);
+				finish_urb(ohci, urb, 0);
 			}
 		}
 		if (completed && !list_empty (&ed->td_list))
@@ -998,6 +981,8 @@
 
 		/* ED's now officially unlinked, hc doesn't see */
 		ed->state = ED_IDLE;
+		if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT)
+			ohci->eds_scheduled--;
 		ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H);
 		ed->hwNextED = 0;
 		wmb ();
@@ -1021,7 +1006,7 @@
 
 		if (ohci->ed_controltail) {
 			command |= OHCI_CLF;
-			if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+			if (quirk_zfmicro(ohci))
 				mdelay(1);
 			if (!(ohci->hc_control & OHCI_CTRL_CLE)) {
 				control |= OHCI_CTRL_CLE;
@@ -1031,7 +1016,7 @@
 		}
 		if (ohci->ed_bulktail) {
 			command |= OHCI_BLF;
-			if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+			if (quirk_zfmicro(ohci))
 				mdelay(1);
 			if (!(ohci->hc_control & OHCI_CTRL_BLE)) {
 				control |= OHCI_CTRL_BLE;
@@ -1043,13 +1028,13 @@
 		/* CLE/BLE to enable, CLF/BLF to (maybe) kickstart */
 		if (control) {
 			ohci->hc_control |= control;
-			if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+			if (quirk_zfmicro(ohci))
 				mdelay(1);
 			ohci_writel (ohci, ohci->hc_control,
 					&ohci->regs->control);
 		}
 		if (command) {
-			if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+			if (quirk_zfmicro(ohci))
 				mdelay(1);
 			ohci_writel (ohci, command, &ohci->regs->cmdstatus);
 		}
@@ -1061,11 +1046,60 @@
 /*-------------------------------------------------------------------------*/
 
 /*
+ * Used to take back a TD from the host controller. This would normally be
+ * called from within dl_done_list, however it may be called directly if the
+ * HC no longer sees the TD and it has not appeared on the donelist (after
+ * two frames).  This bug has been observed on ZF Micro systems.
+ */
+static void takeback_td(struct ohci_hcd *ohci, struct td *td)
+{
+	struct urb	*urb = td->urb;
+	urb_priv_t	*urb_priv = urb->hcpriv;
+	struct ed	*ed = td->ed;
+	int		status;
+
+	/* update URB's length and status from TD */
+	status = td_done(ohci, urb, td);
+	urb_priv->td_cnt++;
+
+	/* If all this urb's TDs are done, call complete() */
+	if (urb_priv->td_cnt == urb_priv->length)
+		finish_urb(ohci, urb, status);
+
+	/* clean schedule:  unlink EDs that are no longer busy */
+	if (list_empty(&ed->td_list)) {
+		if (ed->state == ED_OPER)
+			start_ed_unlink(ohci, ed);
+
+	/* ... reenabling halted EDs only after fault cleanup */
+	} else if ((ed->hwINFO & cpu_to_hc32(ohci, ED_SKIP | ED_DEQUEUE))
+			== cpu_to_hc32(ohci, ED_SKIP)) {
+		td = list_entry(ed->td_list.next, struct td, td_list);
+		if (!(td->hwINFO & cpu_to_hc32(ohci, TD_DONE))) {
+			ed->hwINFO &= ~cpu_to_hc32(ohci, ED_SKIP);
+			/* ... hc may need waking-up */
+			switch (ed->type) {
+			case PIPE_CONTROL:
+				ohci_writel(ohci, OHCI_CLF,
+						&ohci->regs->cmdstatus);
+				break;
+			case PIPE_BULK:
+				ohci_writel(ohci, OHCI_BLF,
+						&ohci->regs->cmdstatus);
+				break;
+			}
+		}
+	}
+}
+
+/*
  * Process normal completions (error or success) and clean the schedules.
  *
  * This is the main path for handing urbs back to drivers.  The only other
- * path is finish_unlinks(), which unlinks URBs using ed_rm_list, instead of
- * scanning the (re-reversed) donelist as this does.
+ * normal path is finish_unlinks(), which unlinks URBs using ed_rm_list,
+ * instead of scanning the (re-reversed) donelist as this does.  There's
+ * an abnormal path too, handling a quirk in some Compaq silicon:  URBs
+ * with TDs that appear to be orphaned are directly reclaimed.
  */
 static void
 dl_done_list (struct ohci_hcd *ohci)
@@ -1074,44 +1108,7 @@
 
 	while (td) {
 		struct td	*td_next = td->next_dl_td;
-		struct urb	*urb = td->urb;
-		urb_priv_t	*urb_priv = urb->hcpriv;
-		struct ed	*ed = td->ed;
-
-		/* update URB's length and status from TD */
-		td_done (ohci, urb, td);
-		urb_priv->td_cnt++;
-
-		/* If all this urb's TDs are done, call complete() */
-		if (urb_priv->td_cnt == urb_priv->length)
-			finish_urb (ohci, urb);
-
-		/* clean schedule:  unlink EDs that are no longer busy */
-		if (list_empty (&ed->td_list)) {
-			if (ed->state == ED_OPER)
-				start_ed_unlink (ohci, ed);
-
-		/* ... reenabling halted EDs only after fault cleanup */
-		} else if ((ed->hwINFO & cpu_to_hc32 (ohci,
-						ED_SKIP | ED_DEQUEUE))
-					== cpu_to_hc32 (ohci, ED_SKIP)) {
-			td = list_entry (ed->td_list.next, struct td, td_list);
-			if (!(td->hwINFO & cpu_to_hc32 (ohci, TD_DONE))) {
-				ed->hwINFO &= ~cpu_to_hc32 (ohci, ED_SKIP);
-				/* ... hc may need waking-up */
-				switch (ed->type) {
-				case PIPE_CONTROL:
-					ohci_writel (ohci, OHCI_CLF,
-						&ohci->regs->cmdstatus);
-					break;
-				case PIPE_BULK:
-					ohci_writel (ohci, OHCI_BLF,
-						&ohci->regs->cmdstatus);
-					break;
-				}
-			}
-		}
-
+		takeback_td(ohci, td);
 		td = td_next;
 	}
 }
diff --git a/drivers/usb/host/ohci-ssb.c b/drivers/usb/host/ohci-ssb.c
new file mode 100644
index 0000000..bc3e785
--- /dev/null
+++ b/drivers/usb/host/ohci-ssb.c
@@ -0,0 +1,247 @@
+/*
+ * Sonics Silicon Backplane
+ * Broadcom USB-core OHCI driver
+ *
+ * Copyright 2007 Michael Buesch <mb@bu3sch.de>
+ *
+ * Derived from the OHCI-PCI driver
+ * Copyright 1999 Roman Weissgaerber
+ * Copyright 2000-2002 David Brownell
+ * Copyright 1999 Linus Torvalds
+ * Copyright 1999 Gregory P. Smith
+ *
+ * Derived from the USBcore related parts of Broadcom-SB
+ * Copyright 2005 Broadcom Corporation
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+#include <linux/ssb/ssb.h>
+
+
+#define SSB_OHCI_TMSLOW_HOSTMODE	(1 << 29)
+
+struct ssb_ohci_device {
+	struct ohci_hcd ohci; /* _must_ be at the beginning. */
+
+	u32 enable_flags;
+};
+
+static inline
+struct ssb_ohci_device *hcd_to_ssb_ohci(struct usb_hcd *hcd)
+{
+	return (struct ssb_ohci_device *)(hcd->hcd_priv);
+}
+
+
+static int ssb_ohci_reset(struct usb_hcd *hcd)
+{
+	struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+	struct ohci_hcd *ohci = &ohcidev->ohci;
+	int err;
+
+	ohci_hcd_init(ohci);
+	err = ohci_init(ohci);
+
+	return err;
+}
+
+static int ssb_ohci_start(struct usb_hcd *hcd)
+{
+	struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+	struct ohci_hcd *ohci = &ohcidev->ohci;
+	int err;
+
+	err = ohci_run(ohci);
+	if (err < 0) {
+		ohci_err(ohci, "can't start\n");
+		ohci_stop(hcd);
+	}
+
+	return err;
+}
+
+#ifdef CONFIG_PM
+static int ssb_ohci_hcd_suspend(struct usb_hcd *hcd, pm_message_t message)
+{
+	struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+	struct ohci_hcd *ohci = &ohcidev->ohci;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ohci->lock, flags);
+
+	ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
+	ohci_readl(ohci, &ohci->regs->intrdisable); /* commit write */
+
+	/* make sure snapshot being resumed re-enumerates everything */
+	if (message.event == PM_EVENT_PRETHAW)
+		ohci_usb_reset(ohci);
+
+	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+
+	spin_unlock_irqrestore(&ohci->lock, flags);
+	return 0;
+}
+
+static int ssb_ohci_hcd_resume(struct usb_hcd *hcd)
+{
+	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+	usb_hcd_resume_root_hub(hcd);
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+static const struct hc_driver ssb_ohci_hc_driver = {
+	.description		= "ssb-usb-ohci",
+	.product_desc		= "SSB OHCI Controller",
+	.hcd_priv_size		= sizeof(struct ssb_ohci_device),
+
+	.irq			= ohci_irq,
+	.flags			= HCD_MEMORY | HCD_USB11,
+
+	.reset			= ssb_ohci_reset,
+	.start			= ssb_ohci_start,
+	.stop			= ohci_stop,
+	.shutdown		= ohci_shutdown,
+
+#ifdef CONFIG_PM
+	.suspend		= ssb_ohci_hcd_suspend,
+	.resume			= ssb_ohci_hcd_resume,
+#endif
+
+	.urb_enqueue		= ohci_urb_enqueue,
+	.urb_dequeue		= ohci_urb_dequeue,
+	.endpoint_disable	= ohci_endpoint_disable,
+
+	.get_frame_number	= ohci_get_frame,
+
+	.hub_status_data	= ohci_hub_status_data,
+	.hub_control		= ohci_hub_control,
+	.hub_irq_enable		= ohci_rhsc_enable,
+	.bus_suspend		= ohci_bus_suspend,
+	.bus_resume		= ohci_bus_resume,
+
+	.start_port_reset	= ohci_start_port_reset,
+};
+
+static void ssb_ohci_detach(struct ssb_device *dev)
+{
+	struct usb_hcd *hcd = ssb_get_drvdata(dev);
+
+	usb_remove_hcd(hcd);
+	iounmap(hcd->regs);
+	usb_put_hcd(hcd);
+	ssb_device_disable(dev, 0);
+}
+
+static int ssb_ohci_attach(struct ssb_device *dev)
+{
+	struct ssb_ohci_device *ohcidev;
+	struct usb_hcd *hcd;
+	int err = -ENOMEM;
+	u32 tmp, flags = 0;
+
+	if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV)
+		flags |= SSB_OHCI_TMSLOW_HOSTMODE;
+
+	ssb_device_enable(dev, flags);
+
+	hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev,
+			dev->dev->bus_id);
+	if (!hcd)
+		goto err_dev_disable;
+	ohcidev = hcd_to_ssb_ohci(hcd);
+	ohcidev->enable_flags = flags;
+
+	tmp = ssb_read32(dev, SSB_ADMATCH0);
+	hcd->rsrc_start = ssb_admatch_base(tmp);
+	hcd->rsrc_len = ssb_admatch_size(tmp);
+	hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
+	if (!hcd->regs)
+		goto err_put_hcd;
+	err = usb_add_hcd(hcd, dev->irq, IRQF_SHARED);
+	if (err)
+		goto err_iounmap;
+
+	ssb_set_drvdata(dev, hcd);
+
+	return err;
+
+err_iounmap:
+	iounmap(hcd->regs);
+err_put_hcd:
+	usb_put_hcd(hcd);
+err_dev_disable:
+	ssb_device_disable(dev, flags);
+	return err;
+}
+
+static int ssb_ohci_probe(struct ssb_device *dev,
+		const struct ssb_device_id *id)
+{
+	int err;
+	u16 chipid_top;
+
+	/* USBcores are only connected on embedded devices. */
+	chipid_top = (dev->bus->chip_id & 0xFF00);
+	if (chipid_top != 0x4700 && chipid_top != 0x5300)
+		return -ENODEV;
+
+	/* TODO: Probably need checks here; is the core connected? */
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	/* We currently always attach SSB_DEV_USB11_HOSTDEV
+	 * as HOST OHCI. If we want to attach it as Client device,
+	 * we must branch here and call into the (yet to
+	 * be written) Client mode driver. Same for remove(). */
+
+	err = ssb_ohci_attach(dev);
+
+	return err;
+}
+
+static void ssb_ohci_remove(struct ssb_device *dev)
+{
+	ssb_ohci_detach(dev);
+}
+
+#ifdef CONFIG_PM
+
+static int ssb_ohci_suspend(struct ssb_device *dev, pm_message_t state)
+{
+	ssb_device_disable(dev, 0);
+
+	return 0;
+}
+
+static int ssb_ohci_resume(struct ssb_device *dev)
+{
+	struct usb_hcd *hcd = ssb_get_drvdata(dev);
+	struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+
+	ssb_device_enable(dev, ohcidev->enable_flags);
+
+	return 0;
+}
+
+#else /* !CONFIG_PM */
+#define ssb_ohci_suspend	NULL
+#define ssb_ohci_resume	NULL
+#endif /* CONFIG_PM */
+
+static const struct ssb_device_id ssb_ohci_table[] = {
+	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
+	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
+	SSB_DEVTABLE_END
+};
+MODULE_DEVICE_TABLE(ssb, ssb_ohci_table);
+
+static struct ssb_driver ssb_ohci_driver = {
+	.name		= KBUILD_MODNAME,
+	.id_table	= ssb_ohci_table,
+	.probe		= ssb_ohci_probe,
+	.remove		= ssb_ohci_remove,
+	.suspend	= ssb_ohci_suspend,
+	.resume		= ssb_ohci_resume,
+};
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index 4ada43c..47c5c66 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -398,11 +398,38 @@
 #define	OHCI_QUIRK_BE_MMIO	0x10			/* BE registers */
 #define	OHCI_QUIRK_ZFMICRO	0x20			/* Compaq ZFMicro chipset*/
 #define	OHCI_QUIRK_NEC		0x40			/* lost interrupts */
+#define	OHCI_QUIRK_FRAME_NO	0x80			/* no big endian frame_no shift */
 	// there are also chip quirks/bugs in init logic
 
 	struct work_struct	nec_work;	/* Worker for NEC quirk */
+
+	/* Needed for ZF Micro quirk */
+	struct timer_list	unlink_watchdog;
+	unsigned		eds_scheduled;
+	struct ed		*ed_to_check;
+	unsigned		zf_delay;
 };
 
+#ifdef CONFIG_PCI
+static inline int quirk_nec(struct ohci_hcd *ohci)
+{
+	return ohci->flags & OHCI_QUIRK_NEC;
+}
+static inline int quirk_zfmicro(struct ohci_hcd *ohci)
+{
+	return ohci->flags & OHCI_QUIRK_ZFMICRO;
+}
+#else
+static inline int quirk_nec(struct ohci_hcd *ohci)
+{
+	return 0;
+}
+static inline int quirk_zfmicro(struct ohci_hcd *ohci)
+{
+	return 0;
+}
+#endif
+
 /* convert between an hcd pointer and the corresponding ohci_hcd */
 static inline struct ohci_hcd *hcd_to_ohci (struct usb_hcd *hcd)
 {
@@ -607,15 +634,12 @@
 /* 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.
- *
- * FIXME: Deal with that as a runtime quirk when STB03xxx is ported over
- * to arch/powerpc
  */
 
-#ifdef CONFIG_STB03xxx
-#define OHCI_BE_FRAME_NO_SHIFT	16
+#ifdef CONFIG_PPC_MPC52xx
+#define big_endian_frame_no_quirk(ohci)	(ohci->flags & OHCI_QUIRK_FRAME_NO)
 #else
-#define OHCI_BE_FRAME_NO_SHIFT	0
+#define big_endian_frame_no_quirk(ohci)	0
 #endif
 
 static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
@@ -623,7 +647,8 @@
 	u32 tmp;
 	if (big_endian_desc(ohci)) {
 		tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no);
-		tmp >>= OHCI_BE_FRAME_NO_SHIFT;
+		if (!big_endian_frame_no_quirk(ohci))
+			tmp >>= 16;
 	} else
 		tmp = le32_to_cpup((__force __le32 *)&ohci->hcca->frame_no);
 
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index 40a1de4..ae8ec44 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -782,10 +782,12 @@
 		kfree(td);
 
 		if (urb) {
-			urb->status = -ENODEV;
-			urb->hcpriv = NULL;
+			usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597),
+					urb);
+
 			spin_unlock(&r8a66597->lock);
-			usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb);
+			usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb,
+					-ENODEV);
 			spin_lock(&r8a66597->lock);
 		}
 		break;
@@ -832,7 +834,7 @@
 	info.pipenum = get_empty_pipenum(r8a66597, ep);
 	info.address = get_urb_to_r8a66597_addr(r8a66597, urb);
 	info.epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
-	info.maxpacket = ep->wMaxPacketSize;
+	info.maxpacket = le16_to_cpu(ep->wMaxPacketSize);
 	info.type = get_r8a66597_type(ep->bmAttributes
 				      & USB_ENDPOINT_XFERTYPE_MASK);
 	info.bufnum = get_bufnum(info.pipenum);
@@ -923,7 +925,7 @@
 	r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1);
 
 	for (i = 0; i < 4; i++) {
-		r8a66597_write(r8a66597, p[i], setup_addr);
+		r8a66597_write(r8a66597, cpu_to_le16(p[i]), setup_addr);
 		setup_addr += 2;
 	}
 	r8a66597_write(r8a66597, SUREQ, DCPCTR);
@@ -1032,6 +1034,15 @@
 	pipe_start(r8a66597, td->pipe);
 }
 
+static int is_set_address(unsigned char *setup_packet)
+{
+	if (((setup_packet[0] & USB_TYPE_MASK) == USB_TYPE_STANDARD) &&
+			setup_packet[1] == USB_REQ_SET_ADDRESS)
+		return 1;
+	else
+		return 0;
+}
+
 /* this function must be called with interrupt disabled */
 static int start_transfer(struct r8a66597 *r8a66597, struct r8a66597_td *td)
 {
@@ -1039,7 +1050,7 @@
 
 	switch (td->type) {
 	case USB_PID_SETUP:
-		if (td->urb->setup_packet[1] == USB_REQ_SET_ADDRESS) {
+		if (is_set_address(td->urb->setup_packet)) {
 			td->set_address = 1;
 			td->urb->setup_packet[2] = alloc_usb_address(r8a66597,
 								     td->urb);
@@ -1106,8 +1117,9 @@
 }
 
 /* this function must be called with interrupt disabled */
-static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td,
-		 u16 pipenum, struct urb *urb)
+static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td,
+		u16 pipenum, struct urb *urb, int status)
+__releases(r8a66597->lock) __acquires(r8a66597->lock)
 {
 	int restart = 0;
 	struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597);
@@ -1115,7 +1127,7 @@
 	r8a66597->timeout_map &= ~(1 << pipenum);
 
 	if (likely(td)) {
-		if (td->set_address && urb->status != 0)
+		if (td->set_address && (status != 0 || urb->unlinked))
 			r8a66597->address_map &= ~(1 << urb->setup_packet[2]);
 
 		pipe_toggle_save(r8a66597, td->pipe, urb);
@@ -1130,9 +1142,9 @@
 		if (usb_pipeisoc(urb->pipe))
 			urb->start_frame = r8a66597_get_frame(hcd);
 
-		urb->hcpriv = NULL;
+		usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb);
 		spin_unlock(&r8a66597->lock);
-		usb_hcd_giveback_urb(hcd, urb);
+		usb_hcd_giveback_urb(hcd, urb, status);
 		spin_lock(&r8a66597->lock);
 	}
 
@@ -1146,14 +1158,6 @@
 	}
 }
 
-/* this function must be called with interrupt disabled */
-static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td,
-			   u16 pipenum, struct urb *urb)
-__releases(r8a66597->lock) __acquires(r8a66597->lock)
-{
-	done(r8a66597, td, pipenum, urb);
-}
-
 static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
 {
 	u16 tmp;
@@ -1162,6 +1166,7 @@
 	struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum);
 	struct urb *urb;
 	int finish = 0;
+	int status = 0;
 
 	if (unlikely(!td))
 		return;
@@ -1170,17 +1175,15 @@
 	fifo_change_from_pipe(r8a66597, td->pipe);
 	tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
 	if (unlikely((tmp & FRDY) == 0)) {
-		urb->status = -EPIPE;
 		pipe_stop(r8a66597, td->pipe);
 		pipe_irq_disable(r8a66597, pipenum);
 		err("in fifo not ready (%d)", pipenum);
-		finish_request(r8a66597, td, pipenum, td->urb);
+		finish_request(r8a66597, td, pipenum, td->urb, -EPIPE);
 		return;
 	}
 
 	/* prepare parameters */
 	rcv_len = tmp & DTLN;
-	bufsize = td->maxpacket;
 	if (usb_pipeisoc(urb->pipe)) {
 		buf = (u16 *)(urb->transfer_buffer +
 				urb->iso_frame_desc[td->iso_cnt].offset);
@@ -1189,29 +1192,31 @@
 		buf = (void *)urb->transfer_buffer + urb->actual_length;
 		urb_len = urb->transfer_buffer_length - urb->actual_length;
 	}
-	if (rcv_len < bufsize)
-		size = min(rcv_len, urb_len);
-	else
-		size = min(bufsize, urb_len);
+	bufsize = min(urb_len, (int) td->maxpacket);
+	if (rcv_len <= bufsize) {
+		size = rcv_len;
+	} else {
+		size = bufsize;
+		status = -EOVERFLOW;
+		finish = 1;
+	}
 
 	/* update parameters */
 	urb->actual_length += size;
 	if (rcv_len == 0)
 		td->zero_packet = 1;
-	if ((size % td->maxpacket) > 0) {
+	if (rcv_len < bufsize) {
 		td->short_packet = 1;
-		if (urb->transfer_buffer_length != urb->actual_length &&
-		    urb->transfer_flags & URB_SHORT_NOT_OK)
-			td->urb->status = -EREMOTEIO;
 	}
 	if (usb_pipeisoc(urb->pipe)) {
 		urb->iso_frame_desc[td->iso_cnt].actual_length = size;
-		urb->iso_frame_desc[td->iso_cnt].status = 0;
+		urb->iso_frame_desc[td->iso_cnt].status = status;
 		td->iso_cnt++;
+		finish = 0;
 	}
 
 	/* check transfer finish */
-	if (check_transfer_finish(td, urb)) {
+	if (finish || check_transfer_finish(td, urb)) {
 		pipe_stop(r8a66597, td->pipe);
 		pipe_irq_disable(r8a66597, pipenum);
 		finish = 1;
@@ -1226,11 +1231,8 @@
 					   buf, size);
 	}
 
-	if (finish && pipenum != 0) {
-		if (td->urb->status == -EINPROGRESS)
-			td->urb->status = 0;
-		finish_request(r8a66597, td, pipenum, urb);
-	}
+	if (finish && pipenum != 0)
+		finish_request(r8a66597, td, pipenum, urb, status);
 }
 
 static void packet_write(struct r8a66597 *r8a66597, u16 pipenum)
@@ -1248,11 +1250,10 @@
 	fifo_change_from_pipe(r8a66597, td->pipe);
 	tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
 	if (unlikely((tmp & FRDY) == 0)) {
-		urb->status = -EPIPE;
 		pipe_stop(r8a66597, td->pipe);
 		pipe_irq_disable(r8a66597, pipenum);
 		err("out write fifo not ready. (%d)", pipenum);
-		finish_request(r8a66597, td, pipenum, td->urb);
+		finish_request(r8a66597, td, pipenum, urb, -EPIPE);
 		return;
 	}
 
@@ -1297,7 +1298,7 @@
 }
 
 
-static void check_next_phase(struct r8a66597 *r8a66597)
+static void check_next_phase(struct r8a66597 *r8a66597, int status)
 {
 	struct r8a66597_td *td = r8a66597_get_td(r8a66597, 0);
 	struct urb *urb;
@@ -1310,49 +1311,41 @@
 	switch (td->type) {
 	case USB_PID_IN:
 	case USB_PID_OUT:
-		if (urb->status != -EINPROGRESS) {
-			finish = 1;
-			break;
-		}
 		if (check_transfer_finish(td, urb))
 			td->type = USB_PID_ACK;
 		break;
 	case USB_PID_SETUP:
-		if (urb->status != -EINPROGRESS)
-			finish = 1;
-		else if (urb->transfer_buffer_length == urb->actual_length) {
+		if (urb->transfer_buffer_length == urb->actual_length)
 			td->type = USB_PID_ACK;
-			urb->status = 0;
-		} else if (usb_pipeout(urb->pipe))
+		else if (usb_pipeout(urb->pipe))
 			td->type = USB_PID_OUT;
 		else
 			td->type = USB_PID_IN;
 		break;
 	case USB_PID_ACK:
 		finish = 1;
-		if (urb->status == -EINPROGRESS)
-			urb->status = 0;
 		break;
 	}
 
-	if (finish)
-		finish_request(r8a66597, td, 0, urb);
+	if (finish || status != 0 || urb->unlinked)
+		finish_request(r8a66597, td, 0, urb, status);
 	else
 		start_transfer(r8a66597, td);
 }
 
-static void set_urb_error(struct r8a66597 *r8a66597, u16 pipenum)
+static int get_urb_error(struct r8a66597 *r8a66597, u16 pipenum)
 {
 	struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum);
 
-	if (td && td->urb) {
+	if (td) {
 		u16 pid = r8a66597_read(r8a66597, td->pipe->pipectr) & PID;
 
 		if (pid == PID_NAK)
-			td->urb->status = -ECONNRESET;
+			return -ECONNRESET;
 		else
-			td->urb->status = -EPIPE;
+			return -EPIPE;
 	}
+	return 0;
 }
 
 static void irq_pipe_ready(struct r8a66597 *r8a66597)
@@ -1371,7 +1364,7 @@
 			packet_read(r8a66597, 0);
 		else
 			pipe_irq_disable(r8a66597, 0);
-		check_next_phase(r8a66597);
+		check_next_phase(r8a66597, 0);
 	}
 
 	for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
@@ -1405,7 +1398,7 @@
 		td = r8a66597_get_td(r8a66597, 0);
 		if (td && td->type != USB_PID_OUT)
 			disable_irq_empty(r8a66597, 0);
-		check_next_phase(r8a66597);
+		check_next_phase(r8a66597, 0);
 	}
 
 	for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
@@ -1420,9 +1413,8 @@
 			if ((tmp & INBUFM) == 0) {
 				disable_irq_empty(r8a66597, pipenum);
 				pipe_irq_disable(r8a66597, pipenum);
-				if (td->urb->status == -EINPROGRESS)
-					td->urb->status = 0;
-				finish_request(r8a66597, td, pipenum, td->urb);
+				finish_request(r8a66597, td, pipenum, td->urb,
+						0);
 			}
 		}
 	}
@@ -1433,15 +1425,16 @@
 	u16 check;
 	u16 pipenum;
 	u16 mask;
+	int status;
 
 	mask = r8a66597_read(r8a66597, NRDYSTS)
 	       & r8a66597_read(r8a66597, NRDYENB);
 	r8a66597_write(r8a66597, ~mask, NRDYSTS);
 	if (mask & NRDY0) {
 		cfifo_change(r8a66597, 0);
-		set_urb_error(r8a66597, 0);
+		status = get_urb_error(r8a66597, 0);
 		pipe_irq_disable(r8a66597, 0);
-		check_next_phase(r8a66597);
+		check_next_phase(r8a66597, status);
 	}
 
 	for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
@@ -1452,10 +1445,10 @@
 			if (unlikely(!td))
 				continue;
 
-			set_urb_error(r8a66597, pipenum);
+			status = get_urb_error(r8a66597, pipenum);
 			pipe_irq_disable(r8a66597, pipenum);
 			pipe_stop(r8a66597, td->pipe);
-			finish_request(r8a66597, td, pipenum, td->urb);
+			finish_request(r8a66597, td, pipenum, td->urb, status);
 		}
 	}
 }
@@ -1475,6 +1468,7 @@
 	u16 intsts0, intsts1, intsts2;
 	u16 intenb0, intenb1, intenb2;
 	u16 mask0, mask1, mask2;
+	int status;
 
 	spin_lock(&r8a66597->lock);
 
@@ -1518,12 +1512,12 @@
 		}
 		if (mask1 & SIGN) {
 			r8a66597_write(r8a66597, ~SIGN, INTSTS1);
-			set_urb_error(r8a66597, 0);
-			check_next_phase(r8a66597);
+			status = get_urb_error(r8a66597, 0);
+			check_next_phase(r8a66597, status);
 		}
 		if (mask1 & SACK) {
 			r8a66597_write(r8a66597, ~SACK, INTSTS1);
-			check_next_phase(r8a66597);
+			check_next_phase(r8a66597, 0);
 		}
 	}
 	if (mask0) {
@@ -1722,21 +1716,25 @@
 }
 
 static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
-				struct usb_host_endpoint *hep,
 				struct urb *urb,
 				gfp_t mem_flags)
 {
+	struct usb_host_endpoint *hep = urb->ep;
 	struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
 	struct r8a66597_td *td = NULL;
-	int ret = 0, request = 0;
+	int ret, request = 0;
 	unsigned long flags;
 
 	spin_lock_irqsave(&r8a66597->lock, flags);
 	if (!get_urb_to_r8a66597_dev(r8a66597, urb)) {
 		ret = -ENODEV;
-		goto error;
+		goto error_not_linked;
 	}
 
+	ret = usb_hcd_link_urb_to_ep(hcd, urb);
+	if (ret)
+		goto error_not_linked;
+
 	if (!hep->hcpriv) {
 		hep->hcpriv = kzalloc(sizeof(struct r8a66597_pipe),
 				GFP_ATOMIC);
@@ -1761,15 +1759,7 @@
 	if (list_empty(&r8a66597->pipe_queue[td->pipenum]))
 		request = 1;
 	list_add_tail(&td->queue, &r8a66597->pipe_queue[td->pipenum]);
-
-	spin_lock(&urb->lock);
-	if (urb->status != -EINPROGRESS) {
-		spin_unlock(&urb->lock);
-		ret = -EPIPE;
-		goto error;
-	}
 	urb->hcpriv = td;
-	spin_unlock(&urb->lock);
 
 	if (request) {
 		ret = start_transfer(r8a66597, td);
@@ -1781,26 +1771,36 @@
 		set_td_timer(r8a66597, td);
 
 error:
+	if (ret)
+		usb_hcd_unlink_urb_from_ep(hcd, urb);
+error_not_linked:
 	spin_unlock_irqrestore(&r8a66597->lock, flags);
 	return ret;
 }
 
-static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
+		int status)
 {
 	struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
 	struct r8a66597_td *td;
 	unsigned long flags;
+	int rc;
 
 	spin_lock_irqsave(&r8a66597->lock, flags);
+	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (rc)
+		goto done;
+
 	if (urb->hcpriv) {
 		td = urb->hcpriv;
 		pipe_stop(r8a66597, td->pipe);
 		pipe_irq_disable(r8a66597, td->pipenum);
 		disable_irq_empty(r8a66597, td->pipenum);
-		done(r8a66597, td, td->pipenum, urb);
+		finish_request(r8a66597, td, td->pipenum, urb, status);
 	}
+ done:
 	spin_unlock_irqrestore(&r8a66597->lock, flags);
-	return 0;
+	return rc;
 }
 
 static void r8a66597_endpoint_disable(struct usb_hcd *hcd,
@@ -1830,7 +1830,7 @@
 	td = r8a66597_get_td(r8a66597, pipenum);
 	if (td)
 		urb = td->urb;
-	done(r8a66597, td, pipenum, urb);
+	finish_request(r8a66597, td, pipenum, urb, -ESHUTDOWN);
 	kfree(hep->hcpriv);
 	hep->hcpriv = NULL;
 	spin_unlock_irqrestore(&r8a66597->lock, flags);
@@ -2027,7 +2027,7 @@
 	case GetPortStatus:
 		if (wIndex > R8A66597_MAX_ROOT_HUB)
 			goto error;
-		*(u32 *)buf = rh->port;
+		*(u32 *)buf = cpu_to_le32(rh->port);
 		break;
 	case SetPortFeature:
 		if (wIndex > R8A66597_MAX_ROOT_HUB)
@@ -2126,8 +2126,8 @@
 	struct usb_hcd		*hcd = r8a66597_to_hcd(r8a66597);
 
 	del_timer_sync(&r8a66597->rh_timer);
-	iounmap((void *)r8a66597->reg);
 	usb_remove_hcd(hcd);
+	iounmap((void *)r8a66597->reg);
 	usb_put_hcd(hcd);
 	return 0;
 }
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index 4cfa3ff..94d859a 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -435,14 +435,9 @@
 	if (usb_pipecontrol(urb->pipe))
 		ep->nextpid = USB_PID_SETUP;
 
-	spin_lock(&urb->lock);
-	if (urb->status == -EINPROGRESS)
-		urb->status = status;
-	urb->hcpriv = NULL;
-	spin_unlock(&urb->lock);
-
+	usb_hcd_unlink_urb_from_ep(sl811_to_hcd(sl811), urb);
 	spin_unlock(&sl811->lock);
-	usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb);
+	usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb, status);
 	spin_lock(&sl811->lock);
 
 	/* leave active endpoints in the schedule */
@@ -538,35 +533,21 @@
 						bank + SL11H_XFERCNTREG);
 			if (len > ep->length) {
 				len = ep->length;
-				urb->status = -EOVERFLOW;
+				urbstat = -EOVERFLOW;
 			}
 			urb->actual_length += len;
 			sl811_read_buf(sl811, SL811HS_PACKET_BUF(bank == 0),
 					buf, len);
 			usb_dotoggle(udev, ep->epnum, 0);
-			if (urb->actual_length == urb->transfer_buffer_length)
-				urbstat = 0;
-			else if (len < ep->maxpacket) {
-				if (urb->transfer_flags & URB_SHORT_NOT_OK)
-					urbstat = -EREMOTEIO;
+			if (urbstat == -EINPROGRESS &&
+					(len < ep->maxpacket ||
+						urb->actual_length ==
+						urb->transfer_buffer_length)) {
+				if (usb_pipecontrol(urb->pipe))
+					ep->nextpid = USB_PID_ACK;
 				else
 					urbstat = 0;
 			}
-			if (usb_pipecontrol(urb->pipe)
-					&& (urbstat == -EREMOTEIO
-						|| urbstat == 0)) {
-
-				/* NOTE if the status stage STALLs (why?),
-				 * this reports the wrong urb status.
-				 */
-				spin_lock(&urb->lock);
-				if (urb->status == -EINPROGRESS)
-					urb->status = urbstat;
-				spin_unlock(&urb->lock);
-
-				urb = NULL;
-				ep->nextpid = USB_PID_ACK;
-			}
 			break;
 		case USB_PID_SETUP:
 			// PACKET("...ACK/setup_%02x qh%p\n", bank, ep);
@@ -605,7 +586,7 @@
 				bank, status, ep, urbstat);
 	}
 
-	if (urb && (urbstat != -EINPROGRESS || urb->status != -EINPROGRESS))
+	if (urbstat != -EINPROGRESS || urb->unlinked)
 		finish_request(sl811, ep, urb, urbstat);
 }
 
@@ -807,7 +788,6 @@
 
 static int sl811h_urb_enqueue(
 	struct usb_hcd		*hcd,
-	struct usb_host_endpoint *hep,
 	struct urb		*urb,
 	gfp_t			mem_flags
 ) {
@@ -820,7 +800,8 @@
 	struct sl811h_ep	*ep = NULL;
 	unsigned long		flags;
 	int			i;
-	int			retval = 0;
+	int			retval;
+	struct usb_host_endpoint	*hep = urb->ep;
 
 #ifdef	DISABLE_ISO
 	if (type == PIPE_ISOCHRONOUS)
@@ -838,7 +819,12 @@
 			|| !HC_IS_RUNNING(hcd->state)) {
 		retval = -ENODEV;
 		kfree(ep);
-		goto fail;
+		goto fail_not_linked;
+	}
+	retval = usb_hcd_link_urb_to_ep(hcd, urb);
+	if (retval) {
+		kfree(ep);
+		goto fail_not_linked;
 	}
 
 	if (hep->hcpriv) {
@@ -951,37 +937,31 @@
 		sofirq_on(sl811);
 	}
 
-	/* in case of unlink-during-submit */
-	spin_lock(&urb->lock);
-	if (urb->status != -EINPROGRESS) {
-		spin_unlock(&urb->lock);
-		finish_request(sl811, ep, urb, 0);
-		retval = 0;
-		goto fail;
-	}
 	urb->hcpriv = hep;
-	spin_unlock(&urb->lock);
-
 	start_transfer(sl811);
 	sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable);
 fail:
+	if (retval)
+		usb_hcd_unlink_urb_from_ep(hcd, urb);
+fail_not_linked:
 	spin_unlock_irqrestore(&sl811->lock, flags);
 	return retval;
 }
 
-static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
 	struct sl811		*sl811 = hcd_to_sl811(hcd);
 	struct usb_host_endpoint *hep;
 	unsigned long		flags;
 	struct sl811h_ep	*ep;
-	int			retval = 0;
+	int			retval;
 
 	spin_lock_irqsave(&sl811->lock, flags);
-	hep = urb->hcpriv;
-	if (!hep)
+	retval = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (retval)
 		goto fail;
 
+	hep = urb->hcpriv;
 	ep = hep->hcpriv;
 	if (ep) {
 		/* finish right away if this urb can't be active ...
@@ -1029,8 +1009,8 @@
 			VDBG("dequeue, urb %p active %s; wait4irq\n", urb,
 				(sl811->active_a == ep) ? "A" : "B");
 	} else
-fail:
 		retval = -EINVAL;
+ fail:
 	spin_unlock_irqrestore(&sl811->lock, flags);
 	return retval;
 }
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index b88eb3c..ac283b0 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -51,7 +51,6 @@
 #include <linux/usb.h>
 #include <linux/workqueue.h>
 #include <linux/platform_device.h>
-#include <linux/pci_ids.h>
 #include <linux/mutex.h>
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -184,7 +183,7 @@
 struct u132 {
         struct kref kref;
         struct list_head u132_list;
-        struct semaphore sw_lock;
+        struct mutex sw_lock;
         struct semaphore scheduler_lock;
         struct u132_platform_data *board;
         struct platform_device *platform_dev;
@@ -493,20 +492,20 @@
                 return;
         } else {
                 int retval;
-                down(&u132->sw_lock);
+                mutex_lock(&u132->sw_lock);
                 retval = read_roothub_info(u132);
                 if (retval) {
                         struct usb_hcd *hcd = u132_to_hcd(u132);
                         u132_disable(u132);
                         u132->going = 1;
-                        up(&u132->sw_lock);
+                        mutex_unlock(&u132->sw_lock);
                         usb_hc_died(hcd);
                         ftdi_elan_gone_away(u132->platform_dev);
                         u132_monitor_put_kref(u132);
                         return;
                 } else {
                         u132_monitor_requeue_work(u132, 500);
-                        up(&u132->sw_lock);
+                        mutex_unlock(&u132->sw_lock);
                         return;
                 }
         }
@@ -519,9 +518,8 @@
         unsigned long irqs;
         struct usb_hcd *hcd = u132_to_hcd(u132);
         urb->error_count = 0;
-        urb->status = status;
-        urb->hcpriv = NULL;
         spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+	usb_hcd_unlink_urb_from_ep(hcd, urb);
         endp->queue_next += 1;
         if (ENDP_QUEUE_SIZE > --endp->queue_size) {
                 endp->active = 0;
@@ -543,7 +541,7 @@
         u132_ring_queue_work(u132, ring, 0);
         up(&u132->scheduler_lock);
         u132_endp_put_kref(u132, endp);
-        usb_hcd_giveback_urb(hcd, urb);
+	usb_hcd_giveback_urb(hcd, urb, status);
         return;
 }
 
@@ -559,9 +557,8 @@
         unsigned long irqs;
         struct usb_hcd *hcd = u132_to_hcd(u132);
         urb->error_count = 0;
-        urb->status = status;
-        urb->hcpriv = NULL;
         spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+	usb_hcd_unlink_urb_from_ep(hcd, urb);
         endp->queue_next += 1;
         if (ENDP_QUEUE_SIZE > --endp->queue_size) {
                 endp->active = 0;
@@ -576,7 +573,7 @@
                 endp->active = 0;
                 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
                 kfree(urbq);
-        } usb_hcd_giveback_urb(hcd, urb);
+	} usb_hcd_giveback_urb(hcd, urb, status);
         return;
 }
 
@@ -646,12 +643,12 @@
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 struct u132_ring *ring = endp->ring;
                 u8 *u = urb->transfer_buffer + urb->actual_length;
                 u8 *b = buf;
@@ -717,10 +714,10 @@
                         return;
                 }
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -745,12 +742,12 @@
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 struct u132_ring *ring = endp->ring;
                 urb->actual_length += len;
                 endp->toggle_bits = toggle_bits;
@@ -769,10 +766,10 @@
                         return;
                 }
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -798,12 +795,12 @@
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 struct u132_ring *ring = endp->ring;
                 u8 *u = urb->transfer_buffer + urb->actual_length;
                 u8 *b = buf;
@@ -872,10 +869,10 @@
                         return;
                 }
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -899,20 +896,20 @@
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -937,12 +934,12 @@
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 struct u132_ring *ring = endp->ring;
                 u8 *u = urb->transfer_buffer;
                 u8 *b = buf;
@@ -981,10 +978,10 @@
                         return;
                 }
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1008,20 +1005,20 @@
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1046,12 +1043,12 @@
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 if (usb_pipein(urb->pipe)) {
                         int retval;
                         struct u132_ring *ring = endp->ring;
@@ -1078,10 +1075,10 @@
                         return;
                 }
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1107,22 +1104,22 @@
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 u132->addr[0].address = 0;
                 endp->usb_addr = udev->usb_addr;
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1146,12 +1143,12 @@
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 int retval;
                 struct u132_ring *ring = endp->ring;
                 up(&u132->scheduler_lock);
@@ -1163,10 +1160,10 @@
                         u132_hcd_giveback_urb(u132, endp, urb, retval);
                 return;
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1190,20 +1187,20 @@
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1228,12 +1225,12 @@
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 int retval;
                 struct u132_ring *ring = endp->ring;
                 u8 *u = urb->transfer_buffer;
@@ -1252,10 +1249,10 @@
                         u132_hcd_giveback_urb(u132, endp, urb, retval);
                 return;
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1280,12 +1277,12 @@
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 int retval;
                 struct u132_ring *ring = endp->ring;
                 up(&u132->scheduler_lock);
@@ -1297,10 +1294,10 @@
                         u132_hcd_giveback_urb(u132, endp, urb, retval);
                 return;
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1805,10 +1802,10 @@
                 dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov"
                         "ed\n", hcd);
         } else {
-                down(&u132->sw_lock);
+                mutex_lock(&u132->sw_lock);
                 msleep(100);
                 u132_power(u132, 0);
-                up(&u132->sw_lock);
+                mutex_unlock(&u132->sw_lock);
         }
 }
 
@@ -1830,7 +1827,7 @@
                         (pdev->dev.platform_data))->vendor;
                 u16 device = ((struct u132_platform_data *)
                         (pdev->dev.platform_data))->device;
-                down(&u132->sw_lock);
+                mutex_lock(&u132->sw_lock);
                 msleep(10);
                 if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) {
                         u132->flags = OHCI_QUIRK_AMD756;
@@ -1845,7 +1842,7 @@
                         u132->going = 1;
                 }
                 msleep(100);
-                up(&u132->sw_lock);
+                mutex_unlock(&u132->sw_lock);
                 return retval;
         } else {
                 dev_err(&u132->platform_dev->dev, "platform_device missing\n");
@@ -1865,32 +1862,44 @@
                 return -ESHUTDOWN;
         } else {
                 int retval;
-                down(&u132->sw_lock);
+                mutex_lock(&u132->sw_lock);
                 retval = u132_init(u132);
                 if (retval) {
                         u132_disable(u132);
                         u132->going = 1;
                 }
-                up(&u132->sw_lock);
+                mutex_unlock(&u132->sw_lock);
                 return retval;
         }
 }
 
 static int create_endpoint_and_queue_int(struct u132 *u132,
-        struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb,
+	struct u132_udev *udev, struct urb *urb,
         struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
         gfp_t mem_flags)
 {
         struct u132_ring *ring;
         unsigned long irqs;
-        u8 endp_number = ++u132->num_endpoints;
-        struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
-                kmalloc(sizeof(struct u132_endp), mem_flags);
+	int rc;
+	u8 endp_number;
+	struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
+
         if (!endp) {
                 return -ENOMEM;
         }
+
+	spin_lock_init(&endp->queue_lock.slock);
+	spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+	rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
+	if (rc) {
+		spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+		kfree(endp);
+		return rc;
+	}
+
+	endp_number = ++u132->num_endpoints;
+	urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
         INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
-        spin_lock_init(&endp->queue_lock.slock);
         INIT_LIST_HEAD(&endp->urb_more);
         ring = endp->ring = &u132->ring[0];
         if (ring->curr_endp) {
@@ -1906,7 +1915,7 @@
         endp->delayed = 0;
         endp->endp_number = endp_number;
         endp->u132 = u132;
-        endp->hep = hep;
+	endp->hep = urb->ep;
         endp->pipetype = usb_pipetype(urb->pipe);
         u132_endp_init_kref(u132, endp);
         if (usb_pipein(urb->pipe)) {
@@ -1925,7 +1934,6 @@
                 u132_udev_get_kref(u132, udev);
         }
         urb->hcpriv = u132;
-        spin_lock_irqsave(&endp->queue_lock.slock, irqs);
         endp->delayed = 1;
         endp->jiffies = jiffies + msecs_to_jiffies(urb->interval);
         endp->udev_number = address;
@@ -1940,8 +1948,8 @@
         return 0;
 }
 
-static int queue_int_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
-        struct usb_host_endpoint *hep, struct urb *urb,
+static int queue_int_on_old_endpoint(struct u132 *u132,
+	struct u132_udev *udev, struct urb *urb,
         struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
         u8 usb_endp, u8 address)
 {
@@ -1965,21 +1973,33 @@
 }
 
 static int create_endpoint_and_queue_bulk(struct u132 *u132,
-        struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb,
+	struct u132_udev *udev, struct urb *urb,
         struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
         gfp_t mem_flags)
 {
         int ring_number;
         struct u132_ring *ring;
         unsigned long irqs;
-        u8 endp_number = ++u132->num_endpoints;
-        struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
-                kmalloc(sizeof(struct u132_endp), mem_flags);
+	int rc;
+	u8 endp_number;
+	struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
+
         if (!endp) {
                 return -ENOMEM;
         }
+
+	spin_lock_init(&endp->queue_lock.slock);
+	spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+	rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
+	if (rc) {
+		spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+		kfree(endp);
+		return rc;
+	}
+
+	endp_number = ++u132->num_endpoints;
+	urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
         INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
-        spin_lock_init(&endp->queue_lock.slock);
         INIT_LIST_HEAD(&endp->urb_more);
         endp->dequeueing = 0;
         endp->edset_flush = 0;
@@ -1987,7 +2007,7 @@
         endp->delayed = 0;
         endp->endp_number = endp_number;
         endp->u132 = u132;
-        endp->hep = hep;
+	endp->hep = urb->ep;
         endp->pipetype = usb_pipetype(urb->pipe);
         u132_endp_init_kref(u132, endp);
         if (usb_pipein(urb->pipe)) {
@@ -2016,7 +2036,6 @@
         }
         ring->length += 1;
         urb->hcpriv = u132;
-        spin_lock_irqsave(&endp->queue_lock.slock, irqs);
         endp->udev_number = address;
         endp->usb_addr = usb_addr;
         endp->usb_endp = usb_endp;
@@ -2030,7 +2049,7 @@
 }
 
 static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
-         struct usb_host_endpoint *hep, struct urb *urb,
+	struct urb *urb,
         struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
         u8 usb_endp, u8 address)
 {
@@ -2052,19 +2071,32 @@
 }
 
 static int create_endpoint_and_queue_control(struct u132 *u132,
-        struct usb_host_endpoint *hep, struct urb *urb,
+	struct urb *urb,
         struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp,
         gfp_t mem_flags)
 {
         struct u132_ring *ring;
-        u8 endp_number = ++u132->num_endpoints;
-        struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
-                kmalloc(sizeof(struct u132_endp), mem_flags);
+	unsigned long irqs;
+	int rc;
+	u8 endp_number;
+	struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
+
         if (!endp) {
                 return -ENOMEM;
         }
+
+	spin_lock_init(&endp->queue_lock.slock);
+	spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+	rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
+	if (rc) {
+		spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+		kfree(endp);
+		return rc;
+	}
+
+	endp_number = ++u132->num_endpoints;
+	urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
         INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
-        spin_lock_init(&endp->queue_lock.slock);
         INIT_LIST_HEAD(&endp->urb_more);
         ring = endp->ring = &u132->ring[0];
         if (ring->curr_endp) {
@@ -2080,11 +2112,10 @@
         endp->delayed = 0;
         endp->endp_number = endp_number;
         endp->u132 = u132;
-        endp->hep = hep;
+	endp->hep = urb->ep;
         u132_endp_init_kref(u132, endp);
         u132_endp_get_kref(u132, endp);
         if (usb_addr == 0) {
-                unsigned long irqs;
                 u8 address = u132->addr[usb_addr].address;
                 struct u132_udev *udev = &u132->udev[address];
                 endp->udev_number = address;
@@ -2098,7 +2129,6 @@
                 udev->endp_number_in[usb_endp] = endp_number;
                 udev->endp_number_out[usb_endp] = endp_number;
                 urb->hcpriv = u132;
-                spin_lock_irqsave(&endp->queue_lock.slock, irqs);
                 endp->queue_size = 1;
                 endp->queue_last = 0;
                 endp->queue_next = 0;
@@ -2107,7 +2137,6 @@
                 u132_endp_queue_work(u132, endp, 0);
                 return 0;
         } else {                /*(usb_addr > 0) */
-                unsigned long irqs;
                 u8 address = u132->addr[usb_addr].address;
                 struct u132_udev *udev = &u132->udev[address];
                 endp->udev_number = address;
@@ -2121,7 +2150,6 @@
                 udev->endp_number_in[usb_endp] = endp_number;
                 udev->endp_number_out[usb_endp] = endp_number;
                 urb->hcpriv = u132;
-                spin_lock_irqsave(&endp->queue_lock.slock, irqs);
                 endp->queue_size = 1;
                 endp->queue_last = 0;
                 endp->queue_next = 0;
@@ -2133,7 +2161,7 @@
 }
 
 static int queue_control_on_old_endpoint(struct u132 *u132,
-        struct usb_host_endpoint *hep, struct urb *urb,
+	struct urb *urb,
         struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
         u8 usb_endp)
 {
@@ -2233,8 +2261,8 @@
         }
 }
 
-static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
-        struct urb *urb, gfp_t mem_flags)
+static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
+		gfp_t mem_flags)
 {
         struct u132 *u132 = hcd_to_u132(hcd);
         if (irqs_disabled()) {
@@ -2249,8 +2277,8 @@
                         , u132->going);
                 return -ENODEV;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 return -ESHUTDOWN;
         } else {
                 u8 usb_addr = usb_pipedevice(urb->pipe);
@@ -2259,16 +2287,24 @@
                 if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
                         u8 address = u132->addr[usb_addr].address;
                         struct u132_udev *udev = &u132->udev[address];
-                        struct u132_endp *endp = hep->hcpriv;
+                        struct u132_endp *endp = urb->ep->hcpriv;
                         urb->actual_length = 0;
                         if (endp) {
                                 unsigned long irqs;
                                 int retval;
                                 spin_lock_irqsave(&endp->queue_lock.slock,
                                         irqs);
-                                retval = queue_int_on_old_endpoint(u132, udev,
-                                        hep, urb, usb_dev, endp, usb_addr,
-                                        usb_endp, address);
+				retval = usb_hcd_link_urb_to_ep(hcd, urb);
+				if (retval == 0) {
+					retval = queue_int_on_old_endpoint(
+							u132, udev, urb,
+							usb_dev, endp,
+							usb_addr, usb_endp,
+							address);
+					if (retval)
+						usb_hcd_unlink_urb_from_ep(
+								hcd, urb);
+				}
                                 spin_unlock_irqrestore(&endp->queue_lock.slock,
                                         irqs);
                                 if (retval) {
@@ -2283,8 +2319,8 @@
                                 return -EINVAL;
                         } else {        /*(endp == NULL) */
                                 return create_endpoint_and_queue_int(u132, udev,
-                                         hep, urb, usb_dev, usb_addr, usb_endp,
-                                        address, mem_flags);
+						urb, usb_dev, usb_addr,
+						usb_endp, address, mem_flags);
                         }
                 } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
                         dev_err(&u132->platform_dev->dev, "the hardware does no"
@@ -2293,16 +2329,24 @@
                 } else if (usb_pipetype(urb->pipe) == PIPE_BULK) {
                         u8 address = u132->addr[usb_addr].address;
                         struct u132_udev *udev = &u132->udev[address];
-                        struct u132_endp *endp = hep->hcpriv;
+                        struct u132_endp *endp = urb->ep->hcpriv;
                         urb->actual_length = 0;
                         if (endp) {
                                 unsigned long irqs;
                                 int retval;
                                 spin_lock_irqsave(&endp->queue_lock.slock,
                                         irqs);
-                                retval = queue_bulk_on_old_endpoint(u132, udev,
-                                        hep, urb, usb_dev, endp, usb_addr,
-                                        usb_endp, address);
+				retval = usb_hcd_link_urb_to_ep(hcd, urb);
+				if (retval == 0) {
+					retval = queue_bulk_on_old_endpoint(
+							u132, udev, urb,
+							usb_dev, endp,
+							usb_addr, usb_endp,
+							address);
+					if (retval)
+						usb_hcd_unlink_urb_from_ep(
+								hcd, urb);
+				}
                                 spin_unlock_irqrestore(&endp->queue_lock.slock,
                                         irqs);
                                 if (retval) {
@@ -2315,10 +2359,10 @@
                                 return -EINVAL;
                         } else
                                 return create_endpoint_and_queue_bulk(u132,
-                                        udev, hep, urb, usb_dev, usb_addr,
+					udev, urb, usb_dev, usb_addr,
                                         usb_endp, address, mem_flags);
                 } else {
-                        struct u132_endp *endp = hep->hcpriv;
+                        struct u132_endp *endp = urb->ep->hcpriv;
                         u16 urb_size = 8;
                         u8 *b = urb->setup_packet;
                         int i = 0;
@@ -2341,9 +2385,16 @@
                                 int retval;
                                 spin_lock_irqsave(&endp->queue_lock.slock,
                                         irqs);
-                                retval = queue_control_on_old_endpoint(u132,
-                                        hep, urb, usb_dev, endp, usb_addr,
-                                        usb_endp);
+				retval = usb_hcd_link_urb_to_ep(hcd, urb);
+				if (retval == 0) {
+					retval = queue_control_on_old_endpoint(
+							u132, urb, usb_dev,
+							endp, usb_addr,
+							usb_endp);
+					if (retval)
+						usb_hcd_unlink_urb_from_ep(
+								hcd, urb);
+				}
                                 spin_unlock_irqrestore(&endp->queue_lock.slock,
                                         irqs);
                                 if (retval) {
@@ -2356,7 +2407,7 @@
                                 return -EINVAL;
                         } else
                                 return create_endpoint_and_queue_control(u132,
-                                        hep, urb, usb_dev, usb_addr, usb_endp,
+					urb, usb_dev, usb_addr, usb_endp,
                                         mem_flags);
                 }
         }
@@ -2375,8 +2426,7 @@
                         list_del(scan);
                         endp->queue_size -= 1;
                         urb->error_count = 0;
-                        urb->hcpriv = NULL;
-                        usb_hcd_giveback_urb(hcd, urb);
+			usb_hcd_giveback_urb(hcd, urb, 0);
                         return 0;
                 } else
                         continue;
@@ -2391,10 +2441,17 @@
 }
 
 static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
-        struct urb *urb)
+		struct urb *urb, int status)
 {
         unsigned long irqs;
+	int rc;
+
         spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+	rc = usb_hcd_check_unlink_urb(u132_to_hcd(u132), urb, status);
+	if (rc) {
+		spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+		return rc;
+	}
         if (endp->queue_size == 0) {
                 dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]"
                         "=%p ring[%d] %c%c usb_endp=%d usb_addr=%d\n", urb,
@@ -2410,11 +2467,10 @@
                         endp->edset_flush = 1;
                         u132_endp_queue_work(u132, endp, 0);
                         spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
-                        urb->hcpriv = NULL;
                         return 0;
                 } else {
                         spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
-                        u132_hcd_abandon_urb(u132, endp, urb, urb->status);
+			u132_hcd_abandon_urb(u132, endp, urb, status);
                         return 0;
                 }
         } else {
@@ -2439,6 +2495,8 @@
                 }
                 if (urb_slot) {
                         struct usb_hcd *hcd = u132_to_hcd(u132);
+
+			usb_hcd_unlink_urb_from_ep(hcd, urb);
                         endp->queue_size -= 1;
                         if (list_empty(&endp->urb_more)) {
                                 spin_unlock_irqrestore(&endp->queue_lock.slock,
@@ -2453,8 +2511,7 @@
                                         irqs);
                                 kfree(urbq);
                         } urb->error_count = 0;
-                        urb->hcpriv = NULL;
-                        usb_hcd_giveback_urb(hcd, urb);
+			usb_hcd_giveback_urb(hcd, urb, status);
                         return 0;
                 } else if (list_empty(&endp->urb_more)) {
                         dev_err(&u132->platform_dev->dev, "urb=%p not found in "
@@ -2468,7 +2525,10 @@
                         spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
                         return -EINVAL;
                 } else {
-                        int retval = dequeue_from_overflow_chain(u132, endp,
+			int retval;
+
+			usb_hcd_unlink_urb_from_ep(u132_to_hcd(u132), urb);
+			retval = dequeue_from_overflow_chain(u132, endp,
                                 urb);
                         spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
                         return retval;
@@ -2476,7 +2536,7 @@
         }
 }
 
-static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
         struct u132 *u132 = hcd_to_u132(hcd);
         if (u132->going > 2) {
@@ -2491,11 +2551,11 @@
                 if (usb_pipein(urb->pipe)) {
                         u8 endp_number = udev->endp_number_in[usb_endp];
                         struct u132_endp *endp = u132->endp[endp_number - 1];
-                        return u132_endp_urb_dequeue(u132, endp, urb);
+                        return u132_endp_urb_dequeue(u132, endp, urb, status);
                 } else {
                         u8 endp_number = udev->endp_number_out[usb_endp];
                         struct u132_endp *endp = u132->endp[endp_number - 1];
-                        return u132_endp_urb_dequeue(u132, endp, urb);
+                        return u132_endp_urb_dequeue(u132, endp, urb, status);
                 }
         }
 }
@@ -2805,7 +2865,7 @@
                 return -ESHUTDOWN;
         } else {
                 int retval = 0;
-                down(&u132->sw_lock);
+                mutex_lock(&u132->sw_lock);
                 switch (typeReq) {
                 case ClearHubFeature:
                         switch (wValue) {
@@ -2868,7 +2928,7 @@
                       stall:retval = -EPIPE;
                         break;
                 }
-                up(&u132->sw_lock);
+                mutex_unlock(&u132->sw_lock);
                 return retval;
         }
 }
@@ -3004,7 +3064,7 @@
                         dev_err(&u132->platform_dev->dev, "removing device u132"
 				".%d\n", u132->sequence_num);
                         msleep(100);
-                        down(&u132->sw_lock);
+                        mutex_lock(&u132->sw_lock);
                         u132_monitor_cancel_work(u132);
                         while (rings-- > 0) {
                                 struct u132_ring *ring = &u132->ring[rings];
@@ -3017,7 +3077,7 @@
                         u132->going += 1;
                         printk(KERN_INFO "removing device u132.%d\n",
                                 u132->sequence_num);
-                        up(&u132->sw_lock);
+                        mutex_unlock(&u132->sw_lock);
                         usb_remove_hcd(hcd);
                         u132_u132_put_kref(u132);
                         return 0;
@@ -3037,7 +3097,7 @@
         u132->platform_dev = pdev;
         u132->power = 0;
         u132->reset = 0;
-        init_MUTEX(&u132->sw_lock);
+        mutex_init(&u132->sw_lock);
         init_MUTEX(&u132->scheduler_lock);
         while (rings-- > 0) {
                 struct u132_ring *ring = &u132->ring[rings];
@@ -3047,7 +3107,7 @@
                 ring->curr_endp = NULL;
                 INIT_DELAYED_WORK(&ring->scheduler,
 				  u132_hcd_ring_work_scheduler);
-        } down(&u132->sw_lock);
+        } mutex_lock(&u132->sw_lock);
         INIT_DELAYED_WORK(&u132->monitor, u132_hcd_monitor_work);
         while (ports-- > 0) {
                 struct u132_port *port = &u132->port[ports];
@@ -3077,7 +3137,7 @@
         while (endps-- > 0) {
                 u132->endp[endps] = NULL;
         }
-        up(&u132->sw_lock);
+        mutex_unlock(&u132->sw_lock);
         return;
 }
 
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
index 1497371..20cc58b 100644
--- a/drivers/usb/host/uhci-debug.c
+++ b/drivers/usb/host/uhci-debug.c
@@ -120,8 +120,8 @@
 	out += sprintf(out, "%s%s", ptype, (urbp->fsbr ? " FSBR" : ""));
 	out += sprintf(out, " Actlen=%d", urbp->urb->actual_length);
 
-	if (urbp->urb->status != -EINPROGRESS)
-		out += sprintf(out, " Status=%d", urbp->urb->status);
+	if (urbp->urb->unlinked)
+		out += sprintf(out, " Unlinked=%d", urbp->urb->unlinked);
 	out += sprintf(out, "\n");
 
 	i = nactive = ninactive = 0;
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
index 1b3d234..340d6ed 100644
--- a/drivers/usb/host/uhci-hcd.h
+++ b/drivers/usb/host/uhci-hcd.h
@@ -146,7 +146,6 @@
 	short phase;			/* Between 0 and period-1 */
 	short load;			/* Periodic time requirement, in us */
 	unsigned int iso_frame;		/* Frame # for iso_packet_desc */
-	int iso_status;			/* Status for Isochronous URBs */
 
 	int state;			/* QH_STATE_xxx; see above */
 	int type;			/* Queue type (control, bulk, etc) */
@@ -457,21 +456,6 @@
 };
 
 
-/*
- * Locking in uhci.c
- *
- * Almost everything relating to the hardware schedule and processing
- * 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->lock while holding urb->lock.
- * The safe order of locking is:
- *
- * #1 uhci->lock
- * #2 urb->lock
- */
-
-
 /* Some special IDs */
 
 #define PCI_VENDOR_ID_GENESYS		0x17a0
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 3bb908c..e5d60d5 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -757,7 +757,6 @@
 		uhci_free_td(uhci, td);
 	}
 
-	urbp->urb->hcpriv = NULL;
 	kmem_cache_free(uhci_up_cachep, urbp);
 }
 
@@ -1324,7 +1323,6 @@
 	if (list_empty(&qh->queue)) {
 		qh->iso_packet_desc = &urb->iso_frame_desc[0];
 		qh->iso_frame = urb->start_frame;
-		qh->iso_status = 0;
 	}
 
 	qh->skel = SKEL_ISO;
@@ -1361,22 +1359,18 @@
 			qh->iso_packet_desc->actual_length = actlength;
 			qh->iso_packet_desc->status = status;
 		}
-
-		if (status) {
+		if (status)
 			urb->error_count++;
-			qh->iso_status = status;
-		}
 
 		uhci_remove_td_from_urbp(td);
 		uhci_free_td(uhci, td);
 		qh->iso_frame += qh->period;
 		++qh->iso_packet_desc;
 	}
-	return qh->iso_status;
+	return 0;
 }
 
 static int uhci_urb_enqueue(struct usb_hcd *hcd,
-		struct usb_host_endpoint *hep,
 		struct urb *urb, gfp_t mem_flags)
 {
 	int ret;
@@ -1387,19 +1381,19 @@
 
 	spin_lock_irqsave(&uhci->lock, flags);
 
-	ret = urb->status;
-	if (ret != -EINPROGRESS)		/* URB already unlinked! */
-		goto done;
+	ret = usb_hcd_link_urb_to_ep(hcd, urb);
+	if (ret)
+		goto done_not_linked;
 
 	ret = -ENOMEM;
 	urbp = uhci_alloc_urb_priv(uhci, urb);
 	if (!urbp)
 		goto done;
 
-	if (hep->hcpriv)
-		qh = (struct uhci_qh *) hep->hcpriv;
+	if (urb->ep->hcpriv)
+		qh = urb->ep->hcpriv;
 	else {
-		qh = uhci_alloc_qh(uhci, urb->dev, hep);
+		qh = uhci_alloc_qh(uhci, urb->dev, urb->ep);
 		if (!qh)
 			goto err_no_qh;
 	}
@@ -1440,27 +1434,29 @@
 err_submit_failed:
 	if (qh->state == QH_STATE_IDLE)
 		uhci_make_qh_idle(uhci, qh);	/* Reclaim unused QH */
-
 err_no_qh:
 	uhci_free_urb_priv(uhci, urbp);
-
 done:
+	if (ret)
+		usb_hcd_unlink_urb_from_ep(hcd, urb);
+done_not_linked:
 	spin_unlock_irqrestore(&uhci->lock, flags);
 	return ret;
 }
 
-static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 	unsigned long flags;
-	struct urb_priv *urbp;
 	struct uhci_qh *qh;
+	int rc;
 
 	spin_lock_irqsave(&uhci->lock, flags);
-	urbp = urb->hcpriv;
-	if (!urbp)			/* URB was never linked! */
+	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (rc)
 		goto done;
-	qh = urbp->qh;
+
+	qh = ((struct urb_priv *) urb->hcpriv)->qh;
 
 	/* Remove Isochronous TDs from the frame list ASAP */
 	if (qh->type == USB_ENDPOINT_XFER_ISOC) {
@@ -1477,14 +1473,14 @@
 
 done:
 	spin_unlock_irqrestore(&uhci->lock, flags);
-	return 0;
+	return rc;
 }
 
 /*
  * Finish unlinking an URB and give it back
  */
 static void uhci_giveback_urb(struct uhci_hcd *uhci, struct uhci_qh *qh,
-		struct urb *urb)
+		struct urb *urb, int status)
 __releases(uhci->lock)
 __acquires(uhci->lock)
 {
@@ -1497,13 +1493,6 @@
 		 * unlinked first.  Regardless, don't confuse people with a
 		 * negative length. */
 		urb->actual_length = max(urb->actual_length, 0);
-
-		/* Report erroneous short transfers */
-		if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
-				urb->actual_length <
-					urb->transfer_buffer_length &&
-				urb->status == 0))
-			urb->status = -EREMOTEIO;
 	}
 
 	/* When giving back the first URB in an Isochronous queue,
@@ -1516,7 +1505,6 @@
 
 		qh->iso_packet_desc = &nurb->iso_frame_desc[0];
 		qh->iso_frame = nurb->start_frame;
-		qh->iso_status = 0;
 	}
 
 	/* Take the URB off the QH's queue.  If the queue is now empty,
@@ -1529,9 +1517,10 @@
 	}
 
 	uhci_free_urb_priv(uhci, urbp);
+	usb_hcd_unlink_urb_from_ep(uhci_to_hcd(uhci), urb);
 
 	spin_unlock(&uhci->lock);
-	usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb);
+	usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb, status);
 	spin_lock(&uhci->lock);
 
 	/* If the queue is now empty, we can unlink the QH and give up its
@@ -1567,24 +1556,17 @@
 		if (status == -EINPROGRESS)
 			break;
 
-		spin_lock(&urb->lock);
-		if (urb->status == -EINPROGRESS)	/* Not dequeued */
-			urb->status = status;
-		else
-			status = ECONNRESET;		/* Not -ECONNRESET */
-		spin_unlock(&urb->lock);
-
 		/* Dequeued but completed URBs can't be given back unless
 		 * the QH is stopped or has finished unlinking. */
-		if (status == ECONNRESET) {
+		if (urb->unlinked) {
 			if (QH_FINISHED_UNLINKING(qh))
 				qh->is_stopped = 1;
 			else if (!qh->is_stopped)
 				return;
 		}
 
-		uhci_giveback_urb(uhci, qh, urb);
-		if (status < 0 && qh->type != USB_ENDPOINT_XFER_ISOC)
+		uhci_giveback_urb(uhci, qh, urb, status);
+		if (status < 0)
 			break;
 	}
 
@@ -1599,7 +1581,7 @@
 restart:
 	list_for_each_entry(urbp, &qh->queue, node) {
 		urb = urbp->urb;
-		if (urb->status != -EINPROGRESS) {
+		if (urb->unlinked) {
 
 			/* Fix up the TD links and save the toggles for
 			 * non-Isochronous queues.  For Isochronous queues,
@@ -1608,7 +1590,7 @@
 				qh->is_stopped = 0;
 				return;
 			}
-			uhci_giveback_urb(uhci, qh, urb);
+			uhci_giveback_urb(uhci, qh, urb, 0);
 			goto restart;
 		}
 	}
diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c
index e9fdbc8..5131cbf 100644
--- a/drivers/usb/misc/adutux.c
+++ b/drivers/usb/misc/adutux.c
@@ -188,7 +188,8 @@
 	spin_lock(&dev->buflock);
 
 	if (status != 0) {
-		if ((status != -ENOENT) && (status != -ECONNRESET)) {
+		if ((status != -ENOENT) && (status != -ECONNRESET) &&
+			(status != -ESHUTDOWN)) {
 			dbg(1," %s : nonzero status received: %d",
 			    __FUNCTION__, status);
 		}
diff --git a/drivers/usb/misc/berry_charge.c b/drivers/usb/misc/berry_charge.c
index 92c1d27..24e2dc3 100644
--- a/drivers/usb/misc/berry_charge.c
+++ b/drivers/usb/misc/berry_charge.c
@@ -71,7 +71,7 @@
 	if (retval != 2) {
 		dev_err(&udev->dev, "First magic command failed: %d.\n",
 			retval);
-		return retval;
+		goto exit;
 	}
 
 	dbg(&udev->dev, "Sending second magic command\n");
@@ -80,7 +80,7 @@
 	if (retval != 0) {
 		dev_err(&udev->dev, "Second magic command failed: %d.\n",
 			retval);
-		return retval;
+		goto exit;
 	}
 
 	dbg(&udev->dev, "Calling set_configuration\n");
@@ -88,6 +88,8 @@
 	if (retval)
 		dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval);
 
+exit:
+	kfree(dummy_buffer);
 	return retval;
 }
 
@@ -112,6 +114,7 @@
 	if (retval)
 		dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval);
 
+	kfree(dummy_buffer);
 	return retval;
 }
 
diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c
index 538b535..d3d8cd6 100644
--- a/drivers/usb/misc/ftdi-elan.c
+++ b/drivers/usb/misc/ftdi-elan.c
@@ -2777,12 +2777,14 @@
         size_t buffer_size;
         int i;
         int retval = -ENOMEM;
-        struct usb_ftdi *ftdi = kmalloc(sizeof(struct usb_ftdi), GFP_KERNEL);
-        if (ftdi == NULL) {
+        struct usb_ftdi *ftdi;
+
+	ftdi = kzalloc(sizeof(struct usb_ftdi), GFP_KERNEL);
+	if (!ftdi) {
                 printk(KERN_ERR "Out of memory\n");
                 return -ENOMEM;
         }
-        memset(ftdi, 0x00, sizeof(struct usb_ftdi));
+
         mutex_lock(&ftdi_module_lock);
         list_add_tail(&ftdi->ftdi_list, &ftdi_static_list);
         ftdi->sequence_num = ++ftdi_instances;
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
index b64ca91..9244d06 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.c
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
@@ -32,7 +32,7 @@
  * * (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>
+ * Author:	Thomas Winischhofer <thomas@winischhofer.net>
  *
  */
 
@@ -962,12 +962,12 @@
 			   packet.address = 0x00000194;
 			   packet.data    = addr;
 			   ret = sisusb_send_bridge_packet(sisusb, 10,
-			   					&packet, 0);
+								&packet, 0);
 			   packet.header  = 0x001f;
 			   packet.address = 0x00000190;
 			   packet.data    = (length & ~3);
 			   ret |= sisusb_send_bridge_packet(sisusb, 10,
-			   					&packet, 0);
+								&packet, 0);
 			   if (sisusb->flagb0 != 0x16) {
 				packet.header  = 0x001f;
 				packet.address = 0x00000180;
@@ -1003,23 +1003,17 @@
 			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);
+					dev_err(&sisusb->sisusb_dev->dev, "Wrote %zd of %d bytes, error %d\n",
+						*bytes_written, length, ret);
 				else if (msgcount == 500)
-					printk(KERN_ERR
-						"sisusbvga[%d]: Too many errors"
-						", logging stopped\n",
-						sisusb->minor);
+					dev_err(&sisusb->sisusb_dev->dev, "Too many errors, logging stopped\n");
 			}
 			addr += (*bytes_written);
 			length -= (*bytes_written);
 	    }
 
 	    if (ret)
-	    	break;
+		break;
 
 	}
 
@@ -1261,51 +1255,10 @@
 				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;
+		break;
 	}
 
 	return ret;
@@ -1401,22 +1354,6 @@
 	return(sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
 }
 
-#if 0
-
-int
-sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data)
-{
-	return(sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
-}
-
-int
-sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data)
-{
-	return(sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
-}
-
-#endif  /*  0  */
-
 int
 sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
 			u32 dest, int length, size_t *bytes_written)
@@ -1446,10 +1383,10 @@
     sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7, &dummy);
 
     for(i = 1; i <= 7; i++) {
-        printk(KERN_DEBUG "sisusb: rwtest %d bytes\n", i);
+        dev_dbg(&sisusb->sisusb_dev->dev, "sisusb: rwtest %d bytes\n", i);
 	sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, i, &dummy);
 	for(j = 0; j < i; j++) {
-	     printk(KERN_DEBUG "sisusb: rwtest read[%d] = %x\n", j, destbuffer[j]);
+	     dev_dbg(&sisusb->sisusb_dev->dev, "rwtest read[%d] = %x\n", j, destbuffer[j]);
 	}
     }
 }
@@ -1533,9 +1470,9 @@
 #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 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)
+#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)
@@ -2008,7 +1945,7 @@
 		SETIREG(SISSR, 0x26, 0x00);
 	}
 
-	SETIREG(SISCR, 0x34, 0x44);  	/* we just set std mode #44 */
+	SETIREG(SISCR, 0x34, 0x44);	/* we just set std mode #44 */
 
 	return ret;
 }
@@ -2168,17 +2105,12 @@
 		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);
+				dev_err(&sisusb->sisusb_dev->dev,"RAM size detection failed, assuming 8MB video RAM\n");
 				ret |= SETIREG(SISSR,0x14,0x31);
 				/* TODO */
 			}
 		} else {
-			printk(KERN_ERR "sisusbvga[%d]: DDR RAM device found, "
-					"assuming 8MB video RAM\n",
-					sisusb->minor);
+			dev_err(&sisusb->sisusb_dev->dev, "DDR RAM device found, assuming 8MB video RAM\n");
 			ret |= SETIREG(SISSR,0x14,0x31);
 			/* *** TODO *** */
 		}
@@ -2249,8 +2181,7 @@
 		break;
 	}
 
-	printk(KERN_INFO "sisusbvga[%d]: %dMB %s %s, bus width %d\n",
-			sisusb->minor, (sisusb->vramsize >> 20), ramtypetext1,
+	dev_info(&sisusb->sisusb_dev->dev, "%dMB %s %s, bus width %d\n", (sisusb->vramsize >> 20), ramtypetext1,
 			ramtypetext2[ramtype], bw);
 }
 
@@ -2509,11 +2440,8 @@
 	struct usb_interface *interface;
 	int subminor = iminor(inode);
 
-	if (!(interface = usb_find_interface(&sisusb_driver, subminor))) {
-		printk(KERN_ERR "sisusb[%d]: Failed to find interface\n",
-				subminor);
+	if (!(interface = usb_find_interface(&sisusb_driver, subminor)))
 		return -ENODEV;
-	}
 
 	if (!(sisusb = usb_get_intfdata(interface)))
 		return -ENODEV;
@@ -2534,18 +2462,12 @@
 		if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) {
 			if (sisusb_init_gfxdevice(sisusb, 0)) {
 				mutex_unlock(&sisusb->lock);
-				printk(KERN_ERR
-					"sisusbvga[%d]: Failed to initialize "
-					"device\n",
-					sisusb->minor);
+				dev_err(&sisusb->sisusb_dev->dev, "Failed to initialize device\n");
 				return -EIO;
 			}
 		} else {
 			mutex_unlock(&sisusb->lock);
-			printk(KERN_ERR
-				"sisusbvga[%d]: Device not attached to "
-				"USB 2.0 hub\n",
-				sisusb->minor);
+			dev_err(&sisusb->sisusb_dev->dev, "Device not attached to USB 2.0 hub\n");
 			return -EIO;
 		}
 	}
@@ -2586,7 +2508,6 @@
 sisusb_release(struct inode *inode, struct file *file)
 {
 	struct sisusb_usb_data *sisusb;
-	int myminor;
 
 	if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
 		return -ENODEV;
@@ -2599,8 +2520,6 @@
 			sisusb_kill_all_busy(sisusb);
 	}
 
-	myminor = sisusb->minor;
-
 	sisusb->isopen = 0;
 	file->private_data = NULL;
 
@@ -2942,7 +2861,7 @@
 sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
 							unsigned long arg)
 {
-	int 	retval, port, length;
+	int	retval, port, length;
 	u32	address;
 
 	/* All our commands require the device
@@ -3065,12 +2984,12 @@
 
 static int
 sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-	     						unsigned long arg)
+							unsigned long arg)
 {
 	struct sisusb_usb_data *sisusb;
 	struct sisusb_info x;
 	struct sisusb_command y;
-	int 	retval = 0;
+	int	retval = 0;
 	u32 __user *argp = (u32 __user *)arg;
 
 	if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
@@ -3095,7 +3014,7 @@
 
 		case SISUSB_GET_CONFIG:
 
-			x.sisusb_id   	    = SISUSB_ID;
+			x.sisusb_id	    = SISUSB_ID;
 			x.sisusb_version    = SISUSB_VERSION;
 			x.sisusb_revision   = SISUSB_REVISION;
 			x.sisusb_patchlevel = SISUSB_PATCHLEVEL;
@@ -3164,7 +3083,7 @@
 	.release =	sisusb_release,
 	.read =		sisusb_read,
 	.write =	sisusb_write,
-	.llseek = 	sisusb_lseek,
+	.llseek =	sisusb_lseek,
 #ifdef SISUSB_NEW_CONFIG_COMPAT
 	.compat_ioctl = sisusb_compat_ioctl,
 #endif
@@ -3183,17 +3102,13 @@
 	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_info(&dev->dev, "USB2VGA dongle found at address %d\n",
 		dev->devnum);
 
 	/* Allocate memory for our private */
 	if (!(sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL))) {
-		printk(KERN_ERR
-			"sisusb: Failed to allocate memory for private data\n");
+		dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for private data\n");
 		return -ENOMEM;
 	}
 	kref_init(&sisusb->kref);
@@ -3202,8 +3117,7 @@
 
 	/* 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_err(&sisusb->sisusb_dev->dev, "Failed to get a minor for device %d\n",
 			dev->devnum);
 		retval = -ENODEV;
 		goto error_1;
@@ -3221,7 +3135,7 @@
 	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);
+		dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for input buffer");
 		retval = -ENOMEM;
 		goto error_2;
 	}
@@ -3233,7 +3147,7 @@
 					GFP_KERNEL,
 					&sisusb->transfer_dma_out[i]))) {
 			if (i == 0) {
-				printk(memfail, "output", sisusb->minor);
+				dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for output buffer\n");
 				retval = -ENOMEM;
 				goto error_3;
 			}
@@ -3245,9 +3159,7 @@
 
 	/* Allocate URBs */
 	if (!(sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL))) {
-		printk(KERN_ERR
-			"sisusbvga[%d]: Failed to allocate URBs\n",
-			sisusb->minor);
+		dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n");
 		retval = -ENOMEM;
 		goto error_3;
 	}
@@ -3255,9 +3167,7 @@
 
 	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);
+			dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n");
 			retval = -ENOMEM;
 			goto error_4;
 		}
@@ -3266,15 +3176,12 @@
 		sisusb->urbstatus[i] = 0;
 	}
 
-	printk(KERN_INFO "sisusbvga[%d]: Allocated %d output buffers\n",
-					sisusb->minor, sisusb->numobufs);
+	dev_info(&sisusb->sisusb_dev->dev, "Allocated %d output buffers\n", sisusb->numobufs);
 
 #ifdef INCL_SISUSB_CON
 	/* Allocate our SiS_Pr */
 	if (!(sisusb->SiS_Pr = kmalloc(sizeof(struct SiS_Private), GFP_KERNEL))) {
-		printk(KERN_ERR
-			"sisusbvga[%d]: Failed to allocate SiS_Pr\n",
-			sisusb->minor);
+		dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate SiS_Pr\n");
 	}
 #endif
 
@@ -3296,10 +3203,7 @@
 	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);
+		dev_err(&sisusb->sisusb_dev->dev, "Error registering ioctl32 translations\n");
 	else
 		sisusb->ioctl32registered = 1;
 	}
@@ -3315,23 +3219,17 @@
 			initscreen = 0;
 #endif
 		if (sisusb_init_gfxdevice(sisusb, initscreen))
-			printk(KERN_ERR
-				"sisusbvga[%d]: Failed to early "
-				"initialize device\n",
-				sisusb->minor);
+			dev_err(&sisusb->sisusb_dev->dev, "Failed to early initialize device\n");
 
 	} else
-		printk(KERN_INFO
-			"sisusbvga[%d]: Not attached to USB 2.0 hub, "
-			"deferring init\n",
-			sisusb->minor);
+		dev_info(&sisusb->sisusb_dev->dev, "Not attached to USB 2.0 hub, deferring init\n");
 
 	sisusb->ready = 1;
 
 #ifdef SISUSBENDIANTEST
-	printk(KERN_DEBUG "sisusb: *** RWTEST ***\n");
+	dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST ***\n");
 	sisusb_testreadwrite(sisusb);
-	printk(KERN_DEBUG "sisusb: *** RWTEST END ***\n");
+	dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST END ***\n");
 #endif
 
 #ifdef INCL_SISUSB_CON
@@ -3354,7 +3252,6 @@
 static void sisusb_disconnect(struct usb_interface *intf)
 {
 	struct sisusb_usb_data *sisusb;
-	int minor;
 
 	/* This should *not* happen */
 	if (!(sisusb = usb_get_intfdata(intf)))
@@ -3364,8 +3261,6 @@
 	sisusb_console_exit(sisusb);
 #endif
 
-	minor = sisusb->minor;
-
 	usb_deregister_dev(intf, &usb_sisusb_class);
 
 	mutex_lock(&sisusb->lock);
@@ -3384,10 +3279,7 @@
 		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);
+			dev_err(&sisusb->sisusb_dev->dev, "Error unregistering ioctl32 translations\n");
 		}
 	}
 #endif
@@ -3400,7 +3292,7 @@
 	/* decrement our usage count */
 	kref_put(&sisusb->kref, sisusb_delete);
 
-	printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor);
+	dev_info(&sisusb->sisusb_dev->dev, "Disconnected\n");
 }
 
 static struct usb_device_id sisusb_table [] = {
@@ -3424,22 +3316,12 @@
 
 static int __init usb_sisusb_init(void)
 {
-	int retval;
 
 #ifdef INCL_SISUSB_CON
 	sisusb_init_concode();
 #endif
 
-	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;
+	return usb_register(&sisusb_driver);
 }
 
 static void __exit usb_sisusb_exit(void)
diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h
index 8e1120a..d2d7872 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.h
+++ b/drivers/usb/misc/sisusbvga/sisusb.h
@@ -8,29 +8,29 @@
  *
  * 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.
+ * 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.
  *
- * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
+ * 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>
  *
  */
 
@@ -44,16 +44,14 @@
 #include <linux/mutex.h>
 
 /* For older kernels, support for text consoles is by default
- * off. To ensable text console support, change the following:
+ * off. To enable text console support, change the following:
  */
-#if 0
-#define CONFIG_USB_SISUSBVGA_CON
-#endif
+/* #define CONFIG_USB_SISUSBVGA_CON */
 
 /* Version Information */
 
 #define SISUSB_VERSION		0
-#define SISUSB_REVISION 	0
+#define SISUSB_REVISION		0
 #define SISUSB_PATCHLEVEL	8
 
 /* Include console and mode switching code? */
@@ -74,7 +72,7 @@
 #define SISUSB_IBUF_SIZE  0x01000
 #define SISUSB_OBUF_SIZE  0x10000	/* fixed */
 
-#define NUMOBUFS 8			/* max number of output buffers/output URBs */
+#define NUMOBUFS 8		/* max number of output buffers/output URBs */
 
 /* About endianness:
  *
@@ -93,7 +91,7 @@
  */
 
 #ifdef __BIG_ENDIAN
-#define SISUSB_CORRECT_ENDIANNESS_PACKET(p) 		\
+#define SISUSB_CORRECT_ENDIANNESS_PACKET(p)		\
 	do {						\
 		p->header  = cpu_to_le16(p->header);	\
 		p->address = cpu_to_le32(p->address);	\
@@ -105,7 +103,7 @@
 
 struct sisusb_usb_data;
 
-struct sisusb_urb_context {		/* urb->context for outbound bulk URBs */
+struct sisusb_urb_context {	/* urb->context for outbound bulk URBs */
 	struct sisusb_usb_data *sisusb;
 	int urbindex;
 	int *actual_length;
@@ -116,16 +114,16 @@
 	struct usb_interface *interface;
 	struct kref kref;
 	wait_queue_head_t wait_q;	/* for syncind and timeouts */
-	struct mutex 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 */
+	struct mutex 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 */
+	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];
@@ -136,13 +134,13 @@
 	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 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 char devinit;	/* device initialized? */
+	unsigned char gfxinit;	/* graphics core initialized? */
 	unsigned short chipid, chipvendor;
 	unsigned short chiprevision;
 #ifdef INCL_SISUSB_CON
@@ -152,7 +150,7 @@
 	int haveconsole, con_first, con_last;
 	int havethisconsole[MAX_NR_CONSOLES];
 	int textmodedestroyed;
-	unsigned int sisusb_num_columns; /* real number, not vt's idea */
+	unsigned int sisusb_num_columns;	/* real number, not vt's idea */
 	int cur_start_addr, con_rolled_over;
 	int sisusb_cursor_loc, bad_cursor_pos;
 	int sisusb_cursor_size_from;
@@ -197,7 +195,7 @@
 	unsigned short header;
 	u32 address;
 	u32 data;
-} __attribute__((__packed__));
+} __attribute__ ((__packed__));
 
 #define CLEARPACKET(packet) memset(packet, 0, 10)
 
@@ -265,36 +263,36 @@
 
 /* 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_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_vrambase;
+	__u32 sisusb_mmiobase;
+	__u32 sisusb_iobase;
+	__u32 sisusb_pcibase;
 
-	__u32	sisusb_vramsize;	/* framebuffer size in bytes */
+	__u32 sisusb_vramsize;	/* framebuffer size in bytes */
 
-	__u32	sisusb_minor;
+	__u32 sisusb_minor;
 
-	__u32   sisusb_fbdevactive;	/* != 0 if framebuffer device active */
+	__u32 sisusb_fbdevactive;	/* != 0 if framebuffer device active */
 
-	__u32   sisusb_conactive;	/* != 0 if console driver active */
+	__u32 sisusb_conactive;	/* != 0 if console driver active */
 
-	__u8	sisusb_reserved[28];	/* for future use */
+	__u8 sisusb_reserved[28];	/* 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 */
+	__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 */
@@ -306,7 +304,7 @@
 
 #define SUCMD_CLRSCR	0x07	/* data0:1:2 = length, data3 = address */
 
-#define SUCMD_HANDLETEXTMODE 0x08 /* Reset/destroy text mode */
+#define SUCMD_HANDLETEXTMODE 0x08	/* Reset/destroy text mode */
 
 #define SUCMD_SETMODE	0x09	/* Set a display mode (data3 = SiS mode) */
 #define SUCMD_SETVESAMODE 0x0a	/* Set a display mode (data3 = VESA mode) */
@@ -315,6 +313,4 @@
 #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/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c
index 8d0edc8..43722e5 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_con.c
+++ b/drivers/usb/misc/sisusbvga/sisusb_con.c
@@ -52,6 +52,7 @@
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/fs.h>
+#include <linux/usb.h>
 #include <linux/tty.h>
 #include <linux/console.h>
 #include <linux/string.h>
@@ -373,14 +374,6 @@
 		return;
 
 	/* sisusb->lock is down */
-
-	/* Don't need to put the character into buffer ourselves,
-	 * because the vt does this BEFORE calling us.
-	 */
-#if 0
-	sisusbcon_writew(ch, SISUSB_VADDR(x, y));
-#endif
-
 	if (sisusb_is_inactive(c, sisusb)) {
 		mutex_unlock(&sisusb->lock);
 		return;
@@ -490,10 +483,6 @@
 	struct sisusb_usb_data *sisusb;
 	ssize_t written;
 	int cols, length;
-#if 0
-	u16 *src, *dest;
-	int i;
-#endif
 
 	if (width <= 0 || height <= 0)
 		return;
@@ -505,41 +494,6 @@
 
 	cols = sisusb->sisusb_num_columns;
 
-	/* Don't need to move data outselves, because
-	 * vt does this BEFORE calling us.
-	 * This is only used by vt's insert/deletechar.
-	 */
-#if 0
-	if (sx == 0 && dx == 0 && width >= c->vc_cols && width <= cols) {
-
-		sisusbcon_memmovew(SISUSB_VADDR(0, dy), SISUSB_VADDR(0, sy),
-					height * width * 2);
-
-	} else if (dy < sy || (dy == sy && dx < sx)) {
-
-		src  = SISUSB_VADDR(sx, sy);
-		dest = SISUSB_VADDR(dx, dy);
-
-		for (i = height; i > 0; i--) {
-			sisusbcon_memmovew(dest, src, width * 2);
-			src  += cols;
-			dest += cols;
-		}
-
-	} else {
-
-		src  = SISUSB_VADDR(sx, sy + height - 1);
-		dest = SISUSB_VADDR(dx, dy + height - 1);
-
-		for (i = height; i > 0; i--) {
-			sisusbcon_memmovew(dest, src, width * 2);
-			src  -= cols;
-			dest -= cols;
-		}
-
-	}
-#endif
-
 	if (sisusb_is_inactive(c, sisusb)) {
 		mutex_unlock(&sisusb->lock);
 		return;
@@ -584,7 +538,7 @@
 	 */
 	if (c->vc_origin == (unsigned long)c->vc_screenbuf) {
 		mutex_unlock(&sisusb->lock);
-		printk(KERN_DEBUG "sisusb: ASSERT ORIGIN != SCREENBUF!\n");
+		dev_dbg(&sisusb->sisusb_dev->dev, "ASSERT ORIGIN != SCREENBUF!\n");
 		return 0;
 	}
 
@@ -1475,7 +1429,7 @@
 int
 sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
 {
-	int i, ret, minor = sisusb->minor;
+	int i, ret;
 
 	mutex_lock(&sisusb->lock);
 
@@ -1508,9 +1462,7 @@
 	/* Set up text mode (and upload  default font) */
 	if (sisusb_reset_text_mode(sisusb, 1)) {
 		mutex_unlock(&sisusb->lock);
-		printk(KERN_ERR
-			"sisusbvga[%d]: Failed to set up text mode\n",
-			minor);
+		dev_err(&sisusb->sisusb_dev->dev, "Failed to set up text mode\n");
 		return 1;
 	}
 
@@ -1531,9 +1483,7 @@
 	/* Allocate screen buffer */
 	if (!(sisusb->scrbuf = (unsigned long)vmalloc(sisusb->scrbuf_size))) {
 		mutex_unlock(&sisusb->lock);
-		printk(KERN_ERR
-			"sisusbvga[%d]: Failed to allocate screen buffer\n",
-			minor);
+		dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate screen buffer\n");
 		return 1;
 	}
 
diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.c b/drivers/usb/misc/sisusbvga/sisusb_init.c
index 9b30f89..273de5d 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_init.c
+++ b/drivers/usb/misc/sisusbvga/sisusb_init.c
@@ -32,7 +32,7 @@
  * * (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>
+ * Author:	Thomas Winischhofer <thomas@winischhofer.net>
  *
  */
 
@@ -55,131 +55,39 @@
 /*         POINTER INITIALIZATION            */
 /*********************************************/
 
-static void
-SiSUSB_InitPtr(struct SiS_Private *SiS_Pr)
+static void SiSUSB_InitPtr(struct SiS_Private *SiS_Pr)
 {
-	SiS_Pr->SiS_ModeResInfo   = SiSUSB_ModeResInfo;
-	SiS_Pr->SiS_StandTable    = SiSUSB_StandTable;
+	SiS_Pr->SiS_ModeResInfo = SiSUSB_ModeResInfo;
+	SiS_Pr->SiS_StandTable = SiSUSB_StandTable;
 
-	SiS_Pr->SiS_SModeIDTable  = SiSUSB_SModeIDTable;
-	SiS_Pr->SiS_EModeIDTable  = SiSUSB_EModeIDTable;
-	SiS_Pr->SiS_RefIndex      = SiSUSB_RefIndex;
-	SiS_Pr->SiS_CRT1Table     = SiSUSB_CRT1Table;
+	SiS_Pr->SiS_SModeIDTable = SiSUSB_SModeIDTable;
+	SiS_Pr->SiS_EModeIDTable = SiSUSB_EModeIDTable;
+	SiS_Pr->SiS_RefIndex = SiSUSB_RefIndex;
+	SiS_Pr->SiS_CRT1Table = SiSUSB_CRT1Table;
 
-	SiS_Pr->SiS_VCLKData      = SiSUSB_VCLKData;
+	SiS_Pr->SiS_VCLKData = SiSUSB_VCLKData;
 }
 
 /*********************************************/
-/*            HELPER: Get ModeID             */
-/*********************************************/
-
-#if 0
-unsigned short
-SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth)
-{
-	unsigned short ModeIndex = 0;
-
-	switch (HDisplay)
-	{
-		case 320:
-			if (VDisplay == 200)
-				ModeIndex = ModeIndex_320x200[Depth];
-			else if (VDisplay == 240)
-				ModeIndex = ModeIndex_320x240[Depth];
-			break;
-		case 400:
-			if (VDisplay == 300)
-				ModeIndex = ModeIndex_400x300[Depth];
-			break;
-		case 512:
-			if (VDisplay == 384)
-				ModeIndex = ModeIndex_512x384[Depth];
-			break;
-		case 640:
-			if (VDisplay == 480)
-				ModeIndex = ModeIndex_640x480[Depth];
-			else if (VDisplay == 400)
-				ModeIndex = ModeIndex_640x400[Depth];
-			break;
-		case 720:
-			if (VDisplay == 480)
-				ModeIndex = ModeIndex_720x480[Depth];
-			else if (VDisplay == 576)
-				ModeIndex = ModeIndex_720x576[Depth];
-			break;
-		case 768:
-			if (VDisplay == 576)
-				ModeIndex = ModeIndex_768x576[Depth];
-			break;
-		case 800:
-			if (VDisplay == 600)
-				ModeIndex = ModeIndex_800x600[Depth];
-			else if (VDisplay == 480)
-				ModeIndex = ModeIndex_800x480[Depth];
-			break;
-		case 848:
-			if (VDisplay == 480)
-				ModeIndex = ModeIndex_848x480[Depth];
-			break;
-		case 856:
-			if (VDisplay == 480)
-				ModeIndex = ModeIndex_856x480[Depth];
-			break;
-		case 960:
-			if (VDisplay == 540)
-				ModeIndex = ModeIndex_960x540[Depth];
-			else if (VDisplay == 600)
-				ModeIndex = ModeIndex_960x600[Depth];
-			break;
-		case 1024:
-			if (VDisplay == 576)
-				ModeIndex = ModeIndex_1024x576[Depth];
-			else if (VDisplay == 768)
-				ModeIndex = ModeIndex_1024x768[Depth];
-			break;
-		case 1152:
-			if (VDisplay == 864)
-				ModeIndex = ModeIndex_1152x864[Depth];
-			break;
-		case 1280:
-			switch (VDisplay) {
-				case 720:
-					ModeIndex = ModeIndex_1280x720[Depth];
-					break;
-				case 768:
-					ModeIndex = ModeIndex_1280x768[Depth];
-					break;
-				case 1024:
-					ModeIndex = ModeIndex_1280x1024[Depth];
-					break;
-			}
-	}
-
-	return ModeIndex;
-}
-#endif  /*  0  */
-
-/*********************************************/
 /*          HELPER: SetReg, GetReg           */
 /*********************************************/
 
 static void
 SiS_SetReg(struct SiS_Private *SiS_Pr, unsigned long port,
-			unsigned short index, unsigned short data)
+	   unsigned short index, unsigned short data)
 {
 	sisusb_setidxreg(SiS_Pr->sisusb, port, index, data);
 }
 
 static void
 SiS_SetRegByte(struct SiS_Private *SiS_Pr, unsigned long port,
-						unsigned short data)
+	       unsigned short data)
 {
 	sisusb_setreg(SiS_Pr->sisusb, port, data);
 }
 
 static unsigned char
-SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port,
-						unsigned short index)
+SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port, unsigned short index)
 {
 	u8 data;
 
@@ -200,22 +108,22 @@
 
 static void
 SiS_SetRegANDOR(struct SiS_Private *SiS_Pr, unsigned long port,
-			unsigned short index, unsigned short DataAND,
-						unsigned short DataOR)
+		unsigned short index, unsigned short DataAND,
+		unsigned short DataOR)
 {
 	sisusb_setidxregandor(SiS_Pr->sisusb, port, index, DataAND, DataOR);
 }
 
 static void
 SiS_SetRegAND(struct SiS_Private *SiS_Pr, unsigned long port,
-			unsigned short index, unsigned short DataAND)
+	      unsigned short index, unsigned short DataAND)
 {
 	sisusb_setidxregand(SiS_Pr->sisusb, port, index, DataAND);
 }
 
 static void
-SiS_SetRegOR(struct SiS_Private *SiS_Pr,unsigned long port,
-			unsigned short index, unsigned short DataOR)
+SiS_SetRegOR(struct SiS_Private *SiS_Pr, unsigned long port,
+	     unsigned short index, unsigned short DataOR)
 {
 	sisusb_setidxregor(SiS_Pr->sisusb, port, index, DataOR);
 }
@@ -224,8 +132,7 @@
 /*      HELPER: DisplayOn, DisplayOff        */
 /*********************************************/
 
-static void
-SiS_DisplayOn(struct SiS_Private *SiS_Pr)
+static void SiS_DisplayOn(struct SiS_Private *SiS_Pr)
 {
 	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, 0xDF);
 }
@@ -234,8 +141,7 @@
 /*        HELPER: Init Port Addresses        */
 /*********************************************/
 
-static void
-SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr)
+static void SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr)
 {
 	SiS_Pr->SiS_P3c4 = BaseAddr + 0x14;
 	SiS_Pr->SiS_P3d4 = BaseAddr + 0x24;
@@ -258,8 +164,7 @@
 /*             HELPER: GetSysFlags           */
 /*********************************************/
 
-static void
-SiS_GetSysFlags(struct SiS_Private *SiS_Pr)
+static void SiS_GetSysFlags(struct SiS_Private *SiS_Pr)
 {
 	SiS_Pr->SiS_MyCR63 = 0x63;
 }
@@ -268,8 +173,7 @@
 /*         HELPER: Init PCI & Engines        */
 /*********************************************/
 
-static void
-SiSInitPCIetc(struct SiS_Private *SiS_Pr)
+static void SiSInitPCIetc(struct SiS_Private *SiS_Pr)
 {
 	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x20, 0xa1);
 	/*  - Enable 2D (0x40)
@@ -285,8 +189,7 @@
 /*        HELPER: SET SEGMENT REGISTERS      */
 /*********************************************/
 
-static void
-SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value)
+static void SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value)
 {
 	unsigned short temp;
 
@@ -299,8 +202,7 @@
 	SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp);
 }
 
-static void
-SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value)
+static void SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value)
 {
 	unsigned short temp;
 
@@ -313,15 +215,13 @@
 	SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp);
 }
 
-static void
-SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value)
+static void SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value)
 {
 	SiS_SetSegRegLower(SiS_Pr, value);
 	SiS_SetSegRegUpper(SiS_Pr, value);
 }
 
-static void
-SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr)
+static void SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr)
 {
 	SiS_SetSegmentReg(SiS_Pr, 0);
 }
@@ -337,14 +237,12 @@
 	SiS_SetSegmentReg(SiS_Pr, value);
 }
 
-static void
-SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr)
+static void SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr)
 {
 	SiS_SetSegmentRegOver(SiS_Pr, 0);
 }
 
-static void
-SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr)
+static void SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr)
 {
 	SiS_ResetSegmentReg(SiS_Pr);
 	SiS_ResetSegmentRegOver(SiS_Pr);
@@ -356,7 +254,7 @@
 
 static int
 SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
-						unsigned short *ModeIdIndex)
+		 unsigned short *ModeIdIndex)
 {
 	if ((*ModeNo) <= 0x13) {
 
@@ -367,12 +265,14 @@
 
 	} else {
 
-		for(*ModeIdIndex = 0; ;(*ModeIdIndex)++) {
+		for (*ModeIdIndex = 0;; (*ModeIdIndex)++) {
 
-			if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == (*ModeNo))
+			if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID ==
+			    (*ModeNo))
 				break;
 
-			if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == 0xFF)
+			if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID ==
+			    0xFF)
 				return 0;
 		}
 
@@ -385,8 +285,7 @@
 /*            HELPER: ENABLE CRT1            */
 /*********************************************/
 
-static void
-SiS_HandleCRT1(struct SiS_Private *SiS_Pr)
+static void SiS_HandleCRT1(struct SiS_Private *SiS_Pr)
 {
 	/* Enable CRT1 gating */
 	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, SiS_Pr->SiS_MyCR63, 0xbf);
@@ -398,9 +297,9 @@
 
 static unsigned short
 SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-		unsigned short ModeIdIndex)
+		  unsigned short ModeIdIndex)
 {
-	static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8};
+	static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8 };
 	unsigned short modeflag;
 	short index;
 
@@ -411,7 +310,8 @@
 	}
 
 	index = (modeflag & ModeTypeMask) - ModeEGA;
-	if (index < 0) index = 0;
+	if (index < 0)
+		index = 0;
 	return ColorDepth[index];
 }
 
@@ -421,7 +321,7 @@
 
 static unsigned short
 SiS_GetOffset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-		unsigned short ModeIdIndex, unsigned short rrti)
+	      unsigned short ModeIdIndex, unsigned short rrti)
 {
 	unsigned short xres, temp, colordepth, infoflag;
 
@@ -458,8 +358,8 @@
 	SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[0] | 0x20;
 	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, SRdata);
 
-	for(i = 2; i <= 4; i++) {
-		SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i-1];
+	for (i = 2; i <= 4; i++) {
+		SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i - 1];
 		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, SRdata);
 	}
 }
@@ -488,7 +388,7 @@
 
 	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f);
 
-	for(i = 0; i <= 0x18; i++) {
+	for (i = 0; i <= 0x18; i++) {
 		CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i];
 		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, i, CRTCdata);
 	}
@@ -504,7 +404,7 @@
 	unsigned char ARdata;
 	unsigned short i;
 
-	for(i = 0; i <= 0x13; i++) {
+	for (i = 0; i <= 0x13; i++) {
 		ARdata = SiS_Pr->SiS_StandTable[StandTableIndex].ATTR[i];
 		SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da);
 		SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, i);
@@ -529,7 +429,7 @@
 	unsigned char GRdata;
 	unsigned short i;
 
-	for(i = 0; i <= 0x08; i++) {
+	for (i = 0; i <= 0x08; i++) {
 		GRdata = SiS_Pr->SiS_StandTable[StandTableIndex].GRC[i];
 		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3ce, i, GRdata);
 	}
@@ -544,12 +444,11 @@
 /*          CLEAR EXTENDED REGISTERS         */
 /*********************************************/
 
-static void
-SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
+static void SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
 {
 	int i;
 
-	for(i = 0x0A; i <= 0x0E; i++) {
+	for (i = 0x0A; i <= 0x0E; i++) {
 		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, 0x00);
 	}
 
@@ -562,15 +461,16 @@
 
 static unsigned short
 SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-					unsigned short ModeIdIndex)
+	       unsigned short ModeIdIndex)
 {
 	unsigned short rrti, i, index, temp;
 
 	if (ModeNo <= 0x13)
 		return 0xFFFF;
 
-	index = SiS_GetReg(SiS_Pr,SiS_Pr->SiS_P3d4, 0x33) & 0x0F;
-	if (index > 0) index--;
+	index = SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x33) & 0x0F;
+	if (index > 0)
+		index--;
 
 	rrti = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex;
 	ModeNo = SiS_Pr->SiS_RefIndex[rrti].ModeID;
@@ -580,13 +480,14 @@
 		if (SiS_Pr->SiS_RefIndex[rrti + i].ModeID != ModeNo)
 			break;
 
-		temp = SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask;
+		temp =
+		    SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask;
 		if (temp < SiS_Pr->SiS_ModeType)
 			break;
 
 		i++;
 		index--;
-	} while(index != 0xFFFF);
+	} while (index != 0xFFFF);
 
 	i--;
 
@@ -597,8 +498,7 @@
 /*                  SYNC                     */
 /*********************************************/
 
-static void
-SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti)
+static void SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti)
 {
 	unsigned short sync = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag >> 8;
 	sync &= 0xC0;
@@ -612,39 +512,40 @@
 
 static void
 SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-			unsigned short ModeIdIndex, unsigned short rrti)
+		unsigned short ModeIdIndex, unsigned short rrti)
 {
-	unsigned char  index;
+	unsigned char index;
 	unsigned short temp, i, j, modeflag;
 
-	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4,0x11,0x7f);
+	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f);
 
 	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
 
 	index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRT1CRTC;
 
-	for(i = 0,j = 0; i <= 7; i++, j++) {
+	for (i = 0, j = 0; i <= 7; i++, j++) {
 		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
-				SiS_Pr->SiS_CRT1Table[index].CR[i]);
+			   SiS_Pr->SiS_CRT1Table[index].CR[i]);
 	}
-	for(j = 0x10; i <= 10; i++, j++) {
+	for (j = 0x10; i <= 10; i++, j++) {
 		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
-				SiS_Pr->SiS_CRT1Table[index].CR[i]);
+			   SiS_Pr->SiS_CRT1Table[index].CR[i]);
 	}
-	for(j = 0x15; i <= 12; i++, j++) {
+	for (j = 0x15; i <= 12; i++, j++) {
 		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
-				SiS_Pr->SiS_CRT1Table[index].CR[i]);
+			   SiS_Pr->SiS_CRT1Table[index].CR[i]);
 	}
-	for(j = 0x0A; i <= 15; i++, j++) {
+	for (j = 0x0A; i <= 15; i++, j++) {
 		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, j,
-				SiS_Pr->SiS_CRT1Table[index].CR[i]);
+			   SiS_Pr->SiS_CRT1Table[index].CR[i]);
 	}
 
 	temp = SiS_Pr->SiS_CRT1Table[index].CR[16] & 0xE0;
-	SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4, 0x0E, temp);
+	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0E, temp);
 
 	temp = ((SiS_Pr->SiS_CRT1Table[index].CR[16]) & 0x01) << 5;
-	if (modeflag & DoubleScanMode)  temp |= 0x80;
+	if (modeflag & DoubleScanMode)
+		temp |= 0x80;
 	SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3d4, 0x09, 0x5F, temp);
 
 	if (SiS_Pr->SiS_ModeType > ModeVGA)
@@ -659,10 +560,10 @@
 
 static void
 SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-			unsigned short ModeIdIndex, unsigned short rrti)
+		  unsigned short ModeIdIndex, unsigned short rrti)
 {
 	unsigned short du = SiS_GetOffset(SiS_Pr, ModeNo, ModeIdIndex, rrti);
-	unsigned short infoflag =  SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag;
+	unsigned short infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag;
 	unsigned short temp;
 
 	temp = (du >> 8) & 0x0f;
@@ -670,11 +571,13 @@
 
 	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x13, (du & 0xFF));
 
-	if (infoflag & InterlaceMode) du >>= 1;
+	if (infoflag & InterlaceMode)
+		du >>= 1;
 
 	du <<= 5;
 	temp = (du >> 8) & 0xff;
-	if (du & 0xff) temp++;
+	if (du & 0xff)
+		temp++;
 	temp++;
 	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x10, temp);
 }
@@ -685,17 +588,17 @@
 
 static void
 SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-						unsigned short rrti)
+		unsigned short rrti)
 {
 	unsigned short index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRTVCLK;
 	unsigned short clka = SiS_Pr->SiS_VCLKData[index].SR2B;
 	unsigned short clkb = SiS_Pr->SiS_VCLKData[index].SR2C;
 
-	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4,0x31,0xCF);
+	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x31, 0xCF);
 
-	SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2B,clka);
-	SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2C,clkb);
-	SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2D,0x01);
+	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2B, clka);
+	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2C, clkb);
+	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2D, 0x01);
 }
 
 /*********************************************/
@@ -704,7 +607,7 @@
 
 static void
 SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-							unsigned short mi)
+		    unsigned short mi)
 {
 	unsigned short modeflag = SiS_Pr->SiS_EModeIDTable[mi].Ext_ModeFlag;
 
@@ -729,7 +632,7 @@
 
 static void
 SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-							unsigned short rrti)
+		 unsigned short rrti)
 {
 	unsigned short data = 0, VCLK = 0, index = 0;
 
@@ -738,7 +641,8 @@
 		VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;
 	}
 
-	if (VCLK >= 166) data |= 0x0c;
+	if (VCLK >= 166)
+		data |= 0x0c;
 	SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x32, 0xf3, data);
 
 	if (VCLK >= 166)
@@ -758,7 +662,7 @@
 
 static void
 SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-			unsigned short ModeIdIndex, unsigned short rrti)
+		    unsigned short ModeIdIndex, unsigned short rrti)
 {
 	unsigned short data, infoflag = 0, modeflag;
 
@@ -778,17 +682,22 @@
 			data |= 0x02;
 			data |= ((SiS_Pr->SiS_ModeType - ModeVGA) << 2);
 		}
-		if (infoflag & InterlaceMode) data |= 0x20;
+		if (infoflag & InterlaceMode)
+			data |= 0x20;
 	}
 	SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x06, 0xC0, data);
 
 	data = 0;
 	if (infoflag & InterlaceMode) {
 		/* data = (Hsync / 8) - ((Htotal / 8) / 2) + 3 */
-		unsigned short hrs = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) |
-			((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2)) - 3;
-		unsigned short hto = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) |
-			((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8)) + 5;
+		unsigned short hrs =
+		    (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) |
+		     ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2))
+		    - 3;
+		unsigned short hto =
+		    (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) |
+		     ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8))
+		    + 5;
 		data = hrs - (hto >> 1) + 3;
 	}
 	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x19, (data & 0xFF));
@@ -829,20 +738,26 @@
 
 static void
 SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData,
-		unsigned short shiftflag, unsigned short dl, unsigned short ah,
-		unsigned short al, unsigned short dh)
+	     unsigned short shiftflag, unsigned short dl, unsigned short ah,
+	     unsigned short al, unsigned short dh)
 {
 	unsigned short d1, d2, d3;
 
 	switch (dl) {
-		case  0:
-			d1 = dh; d2 = ah; d3 = al;
-			break;
-		case  1:
-			d1 = ah; d2 = al; d3 = dh;
-			break;
-		default:
-			d1 = al; d2 = dh; d3 = ah;
+	case 0:
+		d1 = dh;
+		d2 = ah;
+		d3 = al;
+		break;
+	case 1:
+		d1 = ah;
+		d2 = al;
+		d3 = dh;
+		break;
+	default:
+		d1 = al;
+		d2 = dh;
+		d3 = ah;
 	}
 	SiS_SetRegByte(SiS_Pr, DACData, (d1 << shiftflag));
 	SiS_SetRegByte(SiS_Pr, DACData, (d2 << shiftflag));
@@ -850,7 +765,8 @@
 }
 
 static void
-SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi)
+SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
+	    unsigned short mi)
 {
 	unsigned short data, data2, time, i, j, k, m, n, o;
 	unsigned short si, di, bx, sf;
@@ -884,41 +800,45 @@
 
 	SiS_SetRegByte(SiS_Pr, DACAddr, 0x00);
 
-	for(i = 0; i < j; i++) {
+	for (i = 0; i < j; i++) {
 		data = table[i];
-		for(k = 0; k < 3; k++) {
+		for (k = 0; k < 3; k++) {
 			data2 = 0;
-			if (data & 0x01) data2 += 0x2A;
-			if (data & 0x02) data2 += 0x15;
+			if (data & 0x01)
+				data2 += 0x2A;
+			if (data & 0x02)
+				data2 += 0x15;
 			SiS_SetRegByte(SiS_Pr, DACData, (data2 << sf));
 			data >>= 2;
 		}
 	}
 
 	if (time == 256) {
-		for(i = 16; i < 32; i++) {
+		for (i = 16; i < 32; i++) {
 			data = table[i] << sf;
-			for(k = 0; k < 3; k++)
+			for (k = 0; k < 3; k++)
 				SiS_SetRegByte(SiS_Pr, DACData, data);
 		}
 		si = 32;
-		for(m = 0; m < 9; m++) {
+		for (m = 0; m < 9; m++) {
 			di = si;
 			bx = si + 4;
-			for(n = 0; n < 3; n++) {
-				for(o = 0; o < 5; o++) {
+			for (n = 0; n < 3; n++) {
+				for (o = 0; o < 5; o++) {
 					SiS_WriteDAC(SiS_Pr, DACData, sf, n,
-						table[di], table[bx], table[si]);
+						     table[di], table[bx],
+						     table[si]);
 					si++;
 				}
 				si -= 2;
-				for(o = 0; o < 3; o++) {
+				for (o = 0; o < 3; o++) {
 					SiS_WriteDAC(SiS_Pr, DACData, sf, n,
-						table[di], table[si], table[bx]);
+						     table[di], table[si],
+						     table[bx]);
 					si--;
 				}
 			}
-		si += 5;
+			si += 5;
 		}
 	}
 }
@@ -929,7 +849,7 @@
 
 static void
 SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-					unsigned short ModeIdIndex)
+		 unsigned short ModeIdIndex)
 {
 	unsigned short StandTableIndex, rrti;
 
@@ -970,11 +890,10 @@
 /*                 SiSSetMode()              */
 /*********************************************/
 
-int
-SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
+int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
 {
 	unsigned short ModeIdIndex;
-	unsigned long  BaseAddr = SiS_Pr->IOAddress;
+	unsigned long BaseAddr = SiS_Pr->IOAddress;
 
 	SiSUSB_InitPtr(SiS_Pr);
 	SiSUSBRegInit(SiS_Pr, BaseAddr);
@@ -990,7 +909,7 @@
 	ModeNo &= 0x7f;
 
 	SiS_Pr->SiS_ModeType =
-		SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask;
+	    SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask;
 
 	SiS_Pr->SiS_SetFlag = LowModeTests;
 
@@ -1008,8 +927,7 @@
 	return 1;
 }
 
-int
-SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo)
+int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo)
 {
 	unsigned short ModeNo = 0;
 	int i;
@@ -1041,7 +959,3 @@
 }
 
 #endif /* INCL_SISUSB_CON */
-
-
-
-
diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.h b/drivers/usb/misc/sisusbvga/sisusb_init.h
index 864bc0e..c46ce42 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_init.h
+++ b/drivers/usb/misc/sisusbvga/sisusb_init.h
@@ -46,7 +46,7 @@
  * * (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>
+ * Author:	Thomas Winischhofer <thomas@winischhofer.net>
  *
  */
 
@@ -76,21 +76,21 @@
 #define CRT2Mode		0x0800
 #define HalfDCLK		0x1000
 #define NoSupportSimuTV		0x2000
-#define NoSupportLCDScale	0x4000 /* SiS bridge: No scaling possible (no matter what panel) */
+#define NoSupportLCDScale	0x4000	/* SiS bridge: No scaling possible (no matter what panel) */
 #define DoubleScanMode		0x8000
 
 /* Infoflag */
 #define SupportTV		0x0008
 #define SupportTV1024		0x0800
-#define SupportCHTV 		0x0800
-#define Support64048060Hz	0x0800  /* Special for 640x480 LCD */
+#define SupportCHTV		0x0800
+#define Support64048060Hz	0x0800	/* Special for 640x480 LCD */
 #define SupportHiVision		0x0010
 #define SupportYPbPr750p	0x1000
 #define SupportLCD		0x0020
 #define SupportRAMDAC2		0x0040	/* All           (<= 100Mhz) */
-#define SupportRAMDAC2_135	0x0100  /* All except DH (<= 135Mhz) */
-#define SupportRAMDAC2_162	0x0200  /* B, C          (<= 162Mhz) */
-#define SupportRAMDAC2_202	0x0400  /* C             (<= 202Mhz) */
+#define SupportRAMDAC2_135	0x0100	/* All except DH (<= 135Mhz) */
+#define SupportRAMDAC2_162	0x0200	/* B, C          (<= 162Mhz) */
+#define SupportRAMDAC2_202	0x0400	/* C             (<= 202Mhz) */
 #define InterlaceMode		0x0080
 #define SyncPP			0x0000
 #define SyncPN			0x4000
@@ -129,7 +129,7 @@
 #define SIS_RI_856x480		19
 #define SIS_RI_1280x768		20
 #define SIS_RI_1400x1050	21
-#define SIS_RI_1152x864		22  /* Up to here SiS conforming */
+#define SIS_RI_1152x864		22	/* Up to here SiS conforming */
 #define SIS_RI_848x480		23
 #define SIS_RI_1360x768		24
 #define SIS_RI_1024x600		25
@@ -147,691 +147,691 @@
 #define SIS_CRT2_PORT_04	0x04 - 0x30
 
 /* Mode numbers */
-static const unsigned short ModeIndex_320x200[]   = {0x59, 0x41, 0x00, 0x4f};
-static const unsigned short ModeIndex_320x240[]   = {0x50, 0x56, 0x00, 0x53};
-static const unsigned short ModeIndex_400x300[]   = {0x51, 0x57, 0x00, 0x54};
-static const unsigned short ModeIndex_512x384[]   = {0x52, 0x58, 0x00, 0x5c};
-static const unsigned short ModeIndex_640x400[]   = {0x2f, 0x5d, 0x00, 0x5e};
-static const unsigned short ModeIndex_640x480[]   = {0x2e, 0x44, 0x00, 0x62};
-static const unsigned short ModeIndex_720x480[]   = {0x31, 0x33, 0x00, 0x35};
-static const unsigned short ModeIndex_720x576[]   = {0x32, 0x34, 0x00, 0x36};
-static const unsigned short ModeIndex_768x576[]   = {0x5f, 0x60, 0x00, 0x61};
-static const unsigned short ModeIndex_800x480[]   = {0x70, 0x7a, 0x00, 0x76};
-static const unsigned short ModeIndex_800x600[]   = {0x30, 0x47, 0x00, 0x63};
-static const unsigned short ModeIndex_848x480[]   = {0x39, 0x3b, 0x00, 0x3e};
-static const unsigned short ModeIndex_856x480[]   = {0x3f, 0x42, 0x00, 0x45};
-static const unsigned short ModeIndex_960x540[]   = {0x1d, 0x1e, 0x00, 0x1f};
-static const unsigned short ModeIndex_960x600[]   = {0x20, 0x21, 0x00, 0x22};
-static const unsigned short ModeIndex_1024x768[]  = {0x38, 0x4a, 0x00, 0x64};
-static const unsigned short ModeIndex_1024x576[]  = {0x71, 0x74, 0x00, 0x77};
-static const unsigned short ModeIndex_1152x864[]  = {0x29, 0x2a, 0x00, 0x2b};
-static const unsigned short ModeIndex_1280x720[]  = {0x79, 0x75, 0x00, 0x78};
-static const unsigned short ModeIndex_1280x768[]  = {0x23, 0x24, 0x00, 0x25};
-static const unsigned short ModeIndex_1280x1024[] = {0x3a, 0x4d, 0x00, 0x65};
+static const unsigned short ModeIndex_320x200[] = { 0x59, 0x41, 0x00, 0x4f };
+static const unsigned short ModeIndex_320x240[] = { 0x50, 0x56, 0x00, 0x53 };
+static const unsigned short ModeIndex_400x300[] = { 0x51, 0x57, 0x00, 0x54 };
+static const unsigned short ModeIndex_512x384[] = { 0x52, 0x58, 0x00, 0x5c };
+static const unsigned short ModeIndex_640x400[] = { 0x2f, 0x5d, 0x00, 0x5e };
+static const unsigned short ModeIndex_640x480[] = { 0x2e, 0x44, 0x00, 0x62 };
+static const unsigned short ModeIndex_720x480[] = { 0x31, 0x33, 0x00, 0x35 };
+static const unsigned short ModeIndex_720x576[] = { 0x32, 0x34, 0x00, 0x36 };
+static const unsigned short ModeIndex_768x576[] = { 0x5f, 0x60, 0x00, 0x61 };
+static const unsigned short ModeIndex_800x480[] = { 0x70, 0x7a, 0x00, 0x76 };
+static const unsigned short ModeIndex_800x600[] = { 0x30, 0x47, 0x00, 0x63 };
+static const unsigned short ModeIndex_848x480[] = { 0x39, 0x3b, 0x00, 0x3e };
+static const unsigned short ModeIndex_856x480[] = { 0x3f, 0x42, 0x00, 0x45 };
+static const unsigned short ModeIndex_960x540[] = { 0x1d, 0x1e, 0x00, 0x1f };
+static const unsigned short ModeIndex_960x600[] = { 0x20, 0x21, 0x00, 0x22 };
+static const unsigned short ModeIndex_1024x768[] = { 0x38, 0x4a, 0x00, 0x64 };
+static const unsigned short ModeIndex_1024x576[] = { 0x71, 0x74, 0x00, 0x77 };
+static const unsigned short ModeIndex_1152x864[] = { 0x29, 0x2a, 0x00, 0x2b };
+static const unsigned short ModeIndex_1280x720[] = { 0x79, 0x75, 0x00, 0x78 };
+static const unsigned short ModeIndex_1280x768[] = { 0x23, 0x24, 0x00, 0x25 };
+static const unsigned short ModeIndex_1280x1024[] = { 0x3a, 0x4d, 0x00, 0x65 };
 
-static const unsigned char SiS_MDA_DAC[] =
-{
-	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-        0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
-        0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
-        0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
-        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-        0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
-        0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
-        0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F
+static const unsigned char SiS_MDA_DAC[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+	0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+	0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+	0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+	0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F
 };
 
-static const unsigned char SiS_CGA_DAC[] =
-{
-        0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
-        0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
-        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
-        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
-        0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
-        0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
-        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
-        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F
+static const unsigned char SiS_CGA_DAC[] = {
+	0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+	0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+	0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+	0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+	0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+	0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+	0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+	0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F
 };
 
-static const unsigned char SiS_EGA_DAC[] =
-{
-        0x00,0x10,0x04,0x14,0x01,0x11,0x05,0x15,
-        0x20,0x30,0x24,0x34,0x21,0x31,0x25,0x35,
-        0x08,0x18,0x0C,0x1C,0x09,0x19,0x0D,0x1D,
-        0x28,0x38,0x2C,0x3C,0x29,0x39,0x2D,0x3D,
-        0x02,0x12,0x06,0x16,0x03,0x13,0x07,0x17,
-        0x22,0x32,0x26,0x36,0x23,0x33,0x27,0x37,
-        0x0A,0x1A,0x0E,0x1E,0x0B,0x1B,0x0F,0x1F,
-        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F
+static const unsigned char SiS_EGA_DAC[] = {
+	0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x05, 0x15,
+	0x20, 0x30, 0x24, 0x34, 0x21, 0x31, 0x25, 0x35,
+	0x08, 0x18, 0x0C, 0x1C, 0x09, 0x19, 0x0D, 0x1D,
+	0x28, 0x38, 0x2C, 0x3C, 0x29, 0x39, 0x2D, 0x3D,
+	0x02, 0x12, 0x06, 0x16, 0x03, 0x13, 0x07, 0x17,
+	0x22, 0x32, 0x26, 0x36, 0x23, 0x33, 0x27, 0x37,
+	0x0A, 0x1A, 0x0E, 0x1E, 0x0B, 0x1B, 0x0F, 0x1F,
+	0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F
 };
 
-static const unsigned char SiS_VGA_DAC[] =
-{
-	0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
-	0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
-	0x00,0x05,0x08,0x0B,0x0E,0x11,0x14,0x18,
-	0x1C,0x20,0x24,0x28,0x2D,0x32,0x38,0x3F,
-	0x00,0x10,0x1F,0x2F,0x3F,0x1F,0x27,0x2F,
-	0x37,0x3F,0x2D,0x31,0x36,0x3A,0x3F,0x00,
-	0x07,0x0E,0x15,0x1C,0x0E,0x11,0x15,0x18,
-	0x1C,0x14,0x16,0x18,0x1A,0x1C,0x00,0x04,
-	0x08,0x0C,0x10,0x08,0x0A,0x0C,0x0E,0x10,
-	0x0B,0x0C,0x0D,0x0F,0x10
+static const unsigned char SiS_VGA_DAC[] = {
+	0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+	0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+	0x00, 0x05, 0x08, 0x0B, 0x0E, 0x11, 0x14, 0x18,
+	0x1C, 0x20, 0x24, 0x28, 0x2D, 0x32, 0x38, 0x3F,
+	0x00, 0x10, 0x1F, 0x2F, 0x3F, 0x1F, 0x27, 0x2F,
+	0x37, 0x3F, 0x2D, 0x31, 0x36, 0x3A, 0x3F, 0x00,
+	0x07, 0x0E, 0x15, 0x1C, 0x0E, 0x11, 0x15, 0x18,
+	0x1C, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x00, 0x04,
+	0x08, 0x0C, 0x10, 0x08, 0x0A, 0x0C, 0x0E, 0x10,
+	0x0B, 0x0C, 0x0D, 0x0F, 0x10
 };
 
-static const struct SiS_St SiSUSB_SModeIDTable[] =
-{
-	{0x03,0x0010,0x18,0x02,0x02,0x00,0x01,0x03,0x40},
-	{0xff,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
+static const struct SiS_St SiSUSB_SModeIDTable[] = {
+	{0x03, 0x0010, 0x18, 0x02, 0x02, 0x00, 0x01, 0x03, 0x40},
+	{0xff, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
 };
 
-static const struct SiS_StResInfo_S SiSUSB_StResInfo[] =
-{
-	{ 640,400},
-	{ 640,350},
-	{ 720,400},
-	{ 720,350},
-	{ 640,480}
+static const struct SiS_StResInfo_S SiSUSB_StResInfo[] = {
+	{640, 400},
+	{640, 350},
+	{720, 400},
+	{720, 350},
+	{640, 480}
 };
 
-static const struct SiS_ModeResInfo SiSUSB_ModeResInfo[] =
-{
-	{  320, 200, 8, 8},   /* 0x00 */
-	{  320, 240, 8, 8},   /* 0x01 */
-	{  320, 400, 8, 8},   /* 0x02 */
-	{  400, 300, 8, 8},   /* 0x03 */
-	{  512, 384, 8, 8},   /* 0x04 */
-	{  640, 400, 8,16},   /* 0x05 */
-	{  640, 480, 8,16},   /* 0x06 */
-	{  800, 600, 8,16},   /* 0x07 */
-	{ 1024, 768, 8,16},   /* 0x08 */
-	{ 1280,1024, 8,16},   /* 0x09 */
-	{ 1600,1200, 8,16},   /* 0x0a */
-	{ 1920,1440, 8,16},   /* 0x0b */
-	{ 2048,1536, 8,16},   /* 0x0c */
-	{  720, 480, 8,16},   /* 0x0d */
-	{  720, 576, 8,16},   /* 0x0e */
-	{ 1280, 960, 8,16},   /* 0x0f */
-	{  800, 480, 8,16},   /* 0x10 */
-	{ 1024, 576, 8,16},   /* 0x11 */
-	{ 1280, 720, 8,16},   /* 0x12 */
-	{  856, 480, 8,16},   /* 0x13 */
-	{ 1280, 768, 8,16},   /* 0x14 */
-	{ 1400,1050, 8,16},   /* 0x15 */
-	{ 1152, 864, 8,16},   /* 0x16 */
-	{  848, 480, 8,16},   /* 0x17 */
-	{ 1360, 768, 8,16},   /* 0x18 */
-	{ 1024, 600, 8,16},   /* 0x19 */
-	{ 1152, 768, 8,16},   /* 0x1a */
-	{  768, 576, 8,16},   /* 0x1b */
-	{ 1360,1024, 8,16},   /* 0x1c */
-	{ 1680,1050, 8,16},   /* 0x1d */
-	{ 1280, 800, 8,16},   /* 0x1e */
-	{ 1920,1080, 8,16},   /* 0x1f */
-	{  960, 540, 8,16},   /* 0x20 */
-	{  960, 600, 8,16}    /* 0x21 */
+static const struct SiS_ModeResInfo SiSUSB_ModeResInfo[] = {
+	{320, 200, 8, 8},	/* 0x00 */
+	{320, 240, 8, 8},	/* 0x01 */
+	{320, 400, 8, 8},	/* 0x02 */
+	{400, 300, 8, 8},	/* 0x03 */
+	{512, 384, 8, 8},	/* 0x04 */
+	{640, 400, 8, 16},	/* 0x05 */
+	{640, 480, 8, 16},	/* 0x06 */
+	{800, 600, 8, 16},	/* 0x07 */
+	{1024, 768, 8, 16},	/* 0x08 */
+	{1280, 1024, 8, 16},	/* 0x09 */
+	{1600, 1200, 8, 16},	/* 0x0a */
+	{1920, 1440, 8, 16},	/* 0x0b */
+	{2048, 1536, 8, 16},	/* 0x0c */
+	{720, 480, 8, 16},	/* 0x0d */
+	{720, 576, 8, 16},	/* 0x0e */
+	{1280, 960, 8, 16},	/* 0x0f */
+	{800, 480, 8, 16},	/* 0x10 */
+	{1024, 576, 8, 16},	/* 0x11 */
+	{1280, 720, 8, 16},	/* 0x12 */
+	{856, 480, 8, 16},	/* 0x13 */
+	{1280, 768, 8, 16},	/* 0x14 */
+	{1400, 1050, 8, 16},	/* 0x15 */
+	{1152, 864, 8, 16},	/* 0x16 */
+	{848, 480, 8, 16},	/* 0x17 */
+	{1360, 768, 8, 16},	/* 0x18 */
+	{1024, 600, 8, 16},	/* 0x19 */
+	{1152, 768, 8, 16},	/* 0x1a */
+	{768, 576, 8, 16},	/* 0x1b */
+	{1360, 1024, 8, 16},	/* 0x1c */
+	{1680, 1050, 8, 16},	/* 0x1d */
+	{1280, 800, 8, 16},	/* 0x1e */
+	{1920, 1080, 8, 16},	/* 0x1f */
+	{960, 540, 8, 16},	/* 0x20 */
+	{960, 600, 8, 16}	/* 0x21 */
 };
 
-static const struct SiS_StandTable SiSUSB_StandTable[] =
-{
+static const struct SiS_StandTable SiSUSB_StandTable[] = {
 	/* MD_3_400 - mode 0x03 - 400 */
 	{
-		0x50,0x18,0x10,0x1000,
-		{ 0x00,0x03,0x00,0x02 },
-		0x67,
-		{ 0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-		  0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,
-		  0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,
-		  0xff },
-		{ 0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
-		  0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
-		  0x0c,0x00,0x0f,0x08 },
-		{ 0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, 0xff }
-	},
+	 0x50, 0x18, 0x10, 0x1000,
+	 {0x00, 0x03, 0x00, 0x02},
+	 0x67,
+	 {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
+	  0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
+	  0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
+	  0xff},
+	 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+	  0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+	  0x0c, 0x00, 0x0f, 0x08},
+	 {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff}
+	 },
 	/* Generic for VGA and higher */
 	{
-		0x00,0x00,0x00,0x0000,
-		{ 0x01,0x0f,0x00,0x0e },
-		0x23,
-		{ 0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
-		  0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
-		  0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
-		  0xff },
-		{ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
-		  0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
-		  0x01,0x00,0x00,0x00 },
-		{ 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f, 0xff }
-	}
+	 0x00, 0x00, 0x00, 0x0000,
+	 {0x01, 0x0f, 0x00, 0x0e},
+	 0x23,
+	 {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e,
+	  0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0xea, 0x8c, 0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3,
+	  0xff},
+	 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	  0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+	  0x01, 0x00, 0x00, 0x00},
+	 {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff}
+	 }
 };
 
-static const struct SiS_Ext SiSUSB_EModeIDTable[] =
-{
-	{0x2e,0x0a1b,0x0101,SIS_RI_640x480,  0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x8 */
-	{0x2f,0x0a1b,0x0100,SIS_RI_640x400,  0x00,0x00,0x05,0x05,0x10, 0}, /* 640x400x8 */
-	{0x30,0x2a1b,0x0103,SIS_RI_800x600,  0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x8 */
-	{0x31,0x4a1b,0x0000,SIS_RI_720x480,  0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x8 */
-	{0x32,0x4a1b,0x0000,SIS_RI_720x576,  0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x8 */
-	{0x33,0x4a1d,0x0000,SIS_RI_720x480,  0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x16 */
-	{0x34,0x6a1d,0x0000,SIS_RI_720x576,  0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x16 */
-	{0x35,0x4a1f,0x0000,SIS_RI_720x480,  0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x32 */
-	{0x36,0x6a1f,0x0000,SIS_RI_720x576,  0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x32 */
-	{0x38,0x0a1b,0x0105,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x8 */
-	{0x3a,0x0e3b,0x0107,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x8 */
-	{0x41,0x9a1d,0x010e,SIS_RI_320x200,  0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x16 */
-	{0x44,0x0a1d,0x0111,SIS_RI_640x480,  0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x16 */
-	{0x47,0x2a1d,0x0114,SIS_RI_800x600,  0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x16 */
-	{0x4a,0x0a3d,0x0117,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x16 */
-	{0x4d,0x0e7d,0x011a,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x16 */
-	{0x50,0x9a1b,0x0132,SIS_RI_320x240,  0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x8  */
-	{0x51,0xba1b,0x0133,SIS_RI_400x300,  0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x8  */
-	{0x52,0xba1b,0x0134,SIS_RI_512x384,  0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x8  */
-	{0x56,0x9a1d,0x0135,SIS_RI_320x240,  0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x16 */
-	{0x57,0xba1d,0x0136,SIS_RI_400x300,  0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x16 */
-	{0x58,0xba1d,0x0137,SIS_RI_512x384,  0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x16 */
-	{0x59,0x9a1b,0x0138,SIS_RI_320x200,  0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x8  */
-	{0x5c,0xba1f,0x0000,SIS_RI_512x384,  0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x32 */
-	{0x5d,0x0a1d,0x0139,SIS_RI_640x400,  0x00,0x00,0x05,0x07,0x10, 0}, /* 640x400x16 */
-	{0x5e,0x0a1f,0x0000,SIS_RI_640x400,  0x00,0x00,0x05,0x07,0x10, 0}, /* 640x400x32 */
-	{0x62,0x0a3f,0x013a,SIS_RI_640x480,  0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x32 */
-	{0x63,0x2a3f,0x013b,SIS_RI_800x600,  0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x32 */
-	{0x64,0x0a7f,0x013c,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x32 */
-	{0x65,0x0eff,0x013d,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x32 */
-	{0x70,0x6a1b,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x8 */
-	{0x71,0x4a1b,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x8 */
-	{0x74,0x4a1d,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x16 */
-	{0x75,0x0a3d,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x16 */
-	{0x76,0x6a1f,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x32 */
-	{0x77,0x4a1f,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x32 */
-	{0x78,0x0a3f,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x32 */
-	{0x79,0x0a3b,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x8 */
-	{0x7a,0x6a1d,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x16 */
-	{0x23,0x0e3b,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x8 */
-	{0x24,0x0e7d,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x16 */
-	{0x25,0x0eff,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x32 */
-	{0x39,0x6a1b,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x00,0x28,-1}, /* 848x480 */
-	{0x3b,0x6a3d,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x00,0x28,-1},
-	{0x3e,0x6a7f,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x00,0x28,-1},
-	{0x3f,0x6a1b,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x00,0x2a,-1}, /* 856x480 */
-	{0x42,0x6a3d,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x00,0x2a,-1},
-	{0x45,0x6a7f,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x00,0x2a,-1},
-	{0x4f,0x9a1f,0x0000,SIS_RI_320x200,  0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x32 */
-	{0x53,0x9a1f,0x0000,SIS_RI_320x240,  0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x32 */
-	{0x54,0xba1f,0x0000,SIS_RI_400x300,  0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x32 */
-	{0x5f,0x6a1b,0x0000,SIS_RI_768x576,  0x00,0x00,0x06,0x06,0x2c,-1}, /* 768x576 */
-	{0x60,0x6a1d,0x0000,SIS_RI_768x576,  0x00,0x00,0x06,0x06,0x2c,-1},
-	{0x61,0x6a3f,0x0000,SIS_RI_768x576,  0x00,0x00,0x06,0x06,0x2c,-1},
-	{0x1d,0x6a1b,0x0000,SIS_RI_960x540,  0x00,0x00,0x00,0x00,0x2d,-1}, /* 960x540 */
-	{0x1e,0x6a3d,0x0000,SIS_RI_960x540,  0x00,0x00,0x00,0x00,0x2d,-1},
-	{0x1f,0x6a7f,0x0000,SIS_RI_960x540,  0x00,0x00,0x00,0x00,0x2d,-1},
-	{0x20,0x6a1b,0x0000,SIS_RI_960x600,  0x00,0x00,0x00,0x00,0x2e,-1}, /* 960x600 */
-	{0x21,0x6a3d,0x0000,SIS_RI_960x600,  0x00,0x00,0x00,0x00,0x2e,-1},
-	{0x22,0x6a7f,0x0000,SIS_RI_960x600,  0x00,0x00,0x00,0x00,0x2e,-1},
-	{0x29,0x4e1b,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1}, /* 1152x864 */
-	{0x2a,0x4e3d,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1},
-	{0x2b,0x4e7f,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1},
-	{0xff,0x0000,0x0000,0,               0x00,0x00,0x00,0x00,0x00,-1}
+static const struct SiS_Ext SiSUSB_EModeIDTable[] = {
+	{0x2e, 0x0a1b, 0x0101, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2},	/* 640x480x8 */
+	{0x2f, 0x0a1b, 0x0100, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x05, 0x10, 0},	/* 640x400x8 */
+	{0x30, 0x2a1b, 0x0103, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3},	/* 800x600x8 */
+	{0x31, 0x4a1b, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1},	/* 720x480x8 */
+	{0x32, 0x4a1b, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1},	/* 720x576x8 */
+	{0x33, 0x4a1d, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1},	/* 720x480x16 */
+	{0x34, 0x6a1d, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1},	/* 720x576x16 */
+	{0x35, 0x4a1f, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1},	/* 720x480x32 */
+	{0x36, 0x6a1f, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1},	/* 720x576x32 */
+	{0x38, 0x0a1b, 0x0105, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4},	/* 1024x768x8 */
+	{0x3a, 0x0e3b, 0x0107, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8},	/* 1280x1024x8 */
+	{0x41, 0x9a1d, 0x010e, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0},	/* 320x200x16 */
+	{0x44, 0x0a1d, 0x0111, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2},	/* 640x480x16 */
+	{0x47, 0x2a1d, 0x0114, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3},	/* 800x600x16 */
+	{0x4a, 0x0a3d, 0x0117, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4},	/* 1024x768x16 */
+	{0x4d, 0x0e7d, 0x011a, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8},	/* 1280x1024x16 */
+	{0x50, 0x9a1b, 0x0132, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2},	/* 320x240x8  */
+	{0x51, 0xba1b, 0x0133, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3},	/* 400x300x8  */
+	{0x52, 0xba1b, 0x0134, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4},	/* 512x384x8  */
+	{0x56, 0x9a1d, 0x0135, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2},	/* 320x240x16 */
+	{0x57, 0xba1d, 0x0136, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3},	/* 400x300x16 */
+	{0x58, 0xba1d, 0x0137, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4},	/* 512x384x16 */
+	{0x59, 0x9a1b, 0x0138, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0},	/* 320x200x8  */
+	{0x5c, 0xba1f, 0x0000, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4},	/* 512x384x32 */
+	{0x5d, 0x0a1d, 0x0139, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x07, 0x10, 0},	/* 640x400x16 */
+	{0x5e, 0x0a1f, 0x0000, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x07, 0x10, 0},	/* 640x400x32 */
+	{0x62, 0x0a3f, 0x013a, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2},	/* 640x480x32 */
+	{0x63, 0x2a3f, 0x013b, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3},	/* 800x600x32 */
+	{0x64, 0x0a7f, 0x013c, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4},	/* 1024x768x32 */
+	{0x65, 0x0eff, 0x013d, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8},	/* 1280x1024x32 */
+	{0x70, 0x6a1b, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1},	/* 800x480x8 */
+	{0x71, 0x4a1b, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1},	/* 1024x576x8 */
+	{0x74, 0x4a1d, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1},	/* 1024x576x16 */
+	{0x75, 0x0a3d, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5},	/* 1280x720x16 */
+	{0x76, 0x6a1f, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1},	/* 800x480x32 */
+	{0x77, 0x4a1f, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1},	/* 1024x576x32 */
+	{0x78, 0x0a3f, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5},	/* 1280x720x32 */
+	{0x79, 0x0a3b, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5},	/* 1280x720x8 */
+	{0x7a, 0x6a1d, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1},	/* 800x480x16 */
+	{0x23, 0x0e3b, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6},	/* 1280x768x8 */
+	{0x24, 0x0e7d, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6},	/* 1280x768x16 */
+	{0x25, 0x0eff, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6},	/* 1280x768x32 */
+	{0x39, 0x6a1b, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28, -1},	/* 848x480 */
+	{0x3b, 0x6a3d, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28,
+	 -1},
+	{0x3e, 0x6a7f, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28,
+	 -1},
+	{0x3f, 0x6a1b, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a, -1},	/* 856x480 */
+	{0x42, 0x6a3d, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a,
+	 -1},
+	{0x45, 0x6a7f, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a,
+	 -1},
+	{0x4f, 0x9a1f, 0x0000, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0},	/* 320x200x32 */
+	{0x53, 0x9a1f, 0x0000, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2},	/* 320x240x32 */
+	{0x54, 0xba1f, 0x0000, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3},	/* 400x300x32 */
+	{0x5f, 0x6a1b, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c, -1},	/* 768x576 */
+	{0x60, 0x6a1d, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c,
+	 -1},
+	{0x61, 0x6a3f, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c,
+	 -1},
+	{0x1d, 0x6a1b, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d, -1},	/* 960x540 */
+	{0x1e, 0x6a3d, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d,
+	 -1},
+	{0x1f, 0x6a7f, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d,
+	 -1},
+	{0x20, 0x6a1b, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e, -1},	/* 960x600 */
+	{0x21, 0x6a3d, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e,
+	 -1},
+	{0x22, 0x6a7f, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e,
+	 -1},
+	{0x29, 0x4e1b, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33, -1},	/* 1152x864 */
+	{0x2a, 0x4e3d, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33,
+	 -1},
+	{0x2b, 0x4e7f, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33,
+	 -1},
+	{0xff, 0x0000, 0x0000, 0, 0x00, 0x00, 0x00, 0x00, 0x00, -1}
 };
 
-static const struct SiS_Ext2 SiSUSB_RefIndex[] =
-{
-	{0x085f,0x0d,0x03,0x05,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x0 */
-	{0x0067,0x0e,0x04,0x05,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x1 */
-	{0x0067,0x0f,0x08,0x48,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x2 */
-	{0x0067,0x10,0x07,0x8b,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x3 */
-	{0x0047,0x11,0x0a,0x00,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x4 */
-	{0x0047,0x12,0x0d,0x00,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x5 */
-	{0x0047,0x13,0x13,0x00,0x05,0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x6 */
-	{0x0107,0x14,0x1c,0x00,0x05,0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x7 */
-	{0xc85f,0x05,0x00,0x04,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x8 */
-	{0xc067,0x06,0x02,0x04,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x9 */
-	{0xc067,0x07,0x02,0x47,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xa */
-	{0xc067,0x08,0x03,0x8a,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xb */
-	{0xc047,0x09,0x05,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xc */
-	{0xc047,0x0a,0x09,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xd */
-	{0xc047,0x0b,0x0e,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xe */
-	{0xc047,0x0c,0x15,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xf */
-	{0x487f,0x04,0x00,0x00,0x00,0x2f, 640, 400, 0x30, 0x55, 0x6e}, /* 0x10 */
-	{0xc06f,0x3c,0x01,0x06,0x13,0x31, 720, 480, 0x30, 0x00, 0x00}, /* 0x11 */
-	{0x006f,0x3d,0x6f,0x06,0x14,0x32, 720, 576, 0x30, 0x00, 0x00}, /* 0x12 (6f was 03) */
-	{0x0087,0x15,0x06,0x00,0x06,0x38,1024, 768, 0x30, 0x00, 0x00}, /* 0x13 */
-	{0xc877,0x16,0x0b,0x06,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x14 */
-	{0xc067,0x17,0x0f,0x49,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x15 */
-	{0x0067,0x18,0x11,0x00,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x16 */
-	{0x0047,0x19,0x16,0x8c,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x17 */
-	{0x0107,0x1a,0x1b,0x00,0x06,0x38,1024, 768, 0x10, 0x00, 0x00}, /* 0x18 */
-	{0x0107,0x1b,0x1f,0x00,0x06,0x38,1024, 768, 0x10, 0x00, 0x00}, /* 0x19 */
-	{0x407f,0x00,0x00,0x00,0x00,0x41, 320, 200, 0x30, 0x56, 0x4e}, /* 0x1a */
-	{0xc07f,0x01,0x00,0x04,0x04,0x50, 320, 240, 0x30, 0x00, 0x00}, /* 0x1b */
-	{0x007f,0x02,0x04,0x05,0x05,0x51, 400, 300, 0x30, 0x00, 0x00}, /* 0x1c */
-	{0xc077,0x03,0x0b,0x06,0x06,0x52, 512, 384, 0x30, 0x00, 0x00}, /* 0x1d */
-	{0x0077,0x32,0x40,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1e */
-	{0x0047,0x33,0x07,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1f */
-	{0x0047,0x34,0x0a,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x20 */
-	{0x0077,0x35,0x0b,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x21 */
-	{0x0047,0x36,0x11,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x22 */
-	{0x0047,0x37,0x16,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x23 */
-	{0x1137,0x38,0x19,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x24 */
-	{0x1107,0x39,0x1e,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x25 */
-	{0x1307,0x3a,0x20,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x26 */
-	{0x0077,0x42,0x5b,0x08,0x11,0x23,1280, 768, 0x30, 0x00, 0x00}, /* 0x27 */
-	{0x0087,0x45,0x57,0x00,0x16,0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x28 38Hzi  */
-	{0xc067,0x46,0x55,0x0b,0x16,0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x29 848x480-60Hz   */
-	{0x0087,0x47,0x57,0x00,0x17,0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2a 856x480-38Hzi  */
-	{0xc067,0x48,0x57,0x00,0x17,0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2b 856x480-60Hz   */
-	{0x006f,0x4d,0x71,0x06,0x15,0x5f, 768, 576, 0x30, 0x00, 0x00}, /* 0x2c 768x576-56Hz   */
-	{0x0067,0x52,0x6a,0x00,0x1c,0x1d, 960, 540, 0x30, 0x00, 0x00}, /* 0x2d 960x540 60Hz */
-	{0x0077,0x53,0x6b,0x0b,0x1d,0x20, 960, 600, 0x30, 0x00, 0x00}, /* 0x2e 960x600 60Hz */
-	{0x0087,0x1c,0x11,0x00,0x07,0x3a,1280,1024, 0x30, 0x00, 0x00}, /* 0x2f */
-	{0x0137,0x1d,0x19,0x07,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x30 */
-	{0x0107,0x1e,0x1e,0x00,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x31 */
-	{0x0207,0x1f,0x20,0x00,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x32 */
-	{0x0127,0x54,0x6d,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x33 1152x864-60Hz  */
-	{0x0127,0x44,0x19,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x34 1152x864-75Hz  */
-	{0x0127,0x4a,0x1e,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x35 1152x864-85Hz  */
-	{0xffff,0x00,0x00,0x00,0x00,0x00,   0,   0,    0, 0x00, 0x00}
+static const struct SiS_Ext2 SiSUSB_RefIndex[] = {
+	{0x085f, 0x0d, 0x03, 0x05, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00},	/* 0x0 */
+	{0x0067, 0x0e, 0x04, 0x05, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00},	/* 0x1 */
+	{0x0067, 0x0f, 0x08, 0x48, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00},	/* 0x2 */
+	{0x0067, 0x10, 0x07, 0x8b, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00},	/* 0x3 */
+	{0x0047, 0x11, 0x0a, 0x00, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00},	/* 0x4 */
+	{0x0047, 0x12, 0x0d, 0x00, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00},	/* 0x5 */
+	{0x0047, 0x13, 0x13, 0x00, 0x05, 0x30, 800, 600, 0x20, 0x00, 0x00},	/* 0x6 */
+	{0x0107, 0x14, 0x1c, 0x00, 0x05, 0x30, 800, 600, 0x20, 0x00, 0x00},	/* 0x7 */
+	{0xc85f, 0x05, 0x00, 0x04, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},	/* 0x8 */
+	{0xc067, 0x06, 0x02, 0x04, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},	/* 0x9 */
+	{0xc067, 0x07, 0x02, 0x47, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},	/* 0xa */
+	{0xc067, 0x08, 0x03, 0x8a, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},	/* 0xb */
+	{0xc047, 0x09, 0x05, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},	/* 0xc */
+	{0xc047, 0x0a, 0x09, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},	/* 0xd */
+	{0xc047, 0x0b, 0x0e, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},	/* 0xe */
+	{0xc047, 0x0c, 0x15, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},	/* 0xf */
+	{0x487f, 0x04, 0x00, 0x00, 0x00, 0x2f, 640, 400, 0x30, 0x55, 0x6e},	/* 0x10 */
+	{0xc06f, 0x3c, 0x01, 0x06, 0x13, 0x31, 720, 480, 0x30, 0x00, 0x00},	/* 0x11 */
+	{0x006f, 0x3d, 0x6f, 0x06, 0x14, 0x32, 720, 576, 0x30, 0x00, 0x00},	/* 0x12 (6f was 03) */
+	{0x0087, 0x15, 0x06, 0x00, 0x06, 0x38, 1024, 768, 0x30, 0x00, 0x00},	/* 0x13 */
+	{0xc877, 0x16, 0x0b, 0x06, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00},	/* 0x14 */
+	{0xc067, 0x17, 0x0f, 0x49, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00},	/* 0x15 */
+	{0x0067, 0x18, 0x11, 0x00, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00},	/* 0x16 */
+	{0x0047, 0x19, 0x16, 0x8c, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00},	/* 0x17 */
+	{0x0107, 0x1a, 0x1b, 0x00, 0x06, 0x38, 1024, 768, 0x10, 0x00, 0x00},	/* 0x18 */
+	{0x0107, 0x1b, 0x1f, 0x00, 0x06, 0x38, 1024, 768, 0x10, 0x00, 0x00},	/* 0x19 */
+	{0x407f, 0x00, 0x00, 0x00, 0x00, 0x41, 320, 200, 0x30, 0x56, 0x4e},	/* 0x1a */
+	{0xc07f, 0x01, 0x00, 0x04, 0x04, 0x50, 320, 240, 0x30, 0x00, 0x00},	/* 0x1b */
+	{0x007f, 0x02, 0x04, 0x05, 0x05, 0x51, 400, 300, 0x30, 0x00, 0x00},	/* 0x1c */
+	{0xc077, 0x03, 0x0b, 0x06, 0x06, 0x52, 512, 384, 0x30, 0x00, 0x00},	/* 0x1d */
+	{0x0077, 0x32, 0x40, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00},	/* 0x1e */
+	{0x0047, 0x33, 0x07, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00},	/* 0x1f */
+	{0x0047, 0x34, 0x0a, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00},	/* 0x20 */
+	{0x0077, 0x35, 0x0b, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00},	/* 0x21 */
+	{0x0047, 0x36, 0x11, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00},	/* 0x22 */
+	{0x0047, 0x37, 0x16, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00},	/* 0x23 */
+	{0x1137, 0x38, 0x19, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00},	/* 0x24 */
+	{0x1107, 0x39, 0x1e, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00},	/* 0x25 */
+	{0x1307, 0x3a, 0x20, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00},	/* 0x26 */
+	{0x0077, 0x42, 0x5b, 0x08, 0x11, 0x23, 1280, 768, 0x30, 0x00, 0x00},	/* 0x27 */
+	{0x0087, 0x45, 0x57, 0x00, 0x16, 0x39, 848, 480, 0x30, 0x00, 0x00},	/* 0x28 38Hzi  */
+	{0xc067, 0x46, 0x55, 0x0b, 0x16, 0x39, 848, 480, 0x30, 0x00, 0x00},	/* 0x29 848x480-60Hz   */
+	{0x0087, 0x47, 0x57, 0x00, 0x17, 0x3f, 856, 480, 0x30, 0x00, 0x00},	/* 0x2a 856x480-38Hzi  */
+	{0xc067, 0x48, 0x57, 0x00, 0x17, 0x3f, 856, 480, 0x30, 0x00, 0x00},	/* 0x2b 856x480-60Hz   */
+	{0x006f, 0x4d, 0x71, 0x06, 0x15, 0x5f, 768, 576, 0x30, 0x00, 0x00},	/* 0x2c 768x576-56Hz   */
+	{0x0067, 0x52, 0x6a, 0x00, 0x1c, 0x1d, 960, 540, 0x30, 0x00, 0x00},	/* 0x2d 960x540 60Hz */
+	{0x0077, 0x53, 0x6b, 0x0b, 0x1d, 0x20, 960, 600, 0x30, 0x00, 0x00},	/* 0x2e 960x600 60Hz */
+	{0x0087, 0x1c, 0x11, 0x00, 0x07, 0x3a, 1280, 1024, 0x30, 0x00, 0x00},	/* 0x2f */
+	{0x0137, 0x1d, 0x19, 0x07, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00},	/* 0x30 */
+	{0x0107, 0x1e, 0x1e, 0x00, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00},	/* 0x31 */
+	{0x0207, 0x1f, 0x20, 0x00, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00},	/* 0x32 */
+	{0x0127, 0x54, 0x6d, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00},	/* 0x33 1152x864-60Hz  */
+	{0x0127, 0x44, 0x19, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00},	/* 0x34 1152x864-75Hz  */
+	{0x0127, 0x4a, 0x1e, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00},	/* 0x35 1152x864-85Hz  */
+	{0xffff, 0x00, 0x00, 0x00, 0x00, 0x00, 0, 0, 0, 0x00, 0x00}
 };
 
-static const struct SiS_CRT1Table SiSUSB_CRT1Table[] =
-{
- {{0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,
-   0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x00,
-   0x00}}, /* 0x0 */
- {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e,
-   0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00,
-   0x00}}, /* 0x1 */
- {{0x3d,0x31,0x31,0x81,0x37,0x1f,0x72,0xf0,
-   0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x05,
-   0x01}}, /* 0x2 */
- {{0x4f,0x3f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
-   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x01,
-   0x01}}, /* 0x3 */
- {{0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-   0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x05,
-   0x00}}, /* 0x4 */
- {{0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e,
-   0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05,
-   0x00}}, /* 0x5 */
- {{0x63,0x4f,0x4f,0x87,0x56,0x9b,0x06,0x3e,
-   0xe8,0x8a,0xdf,0xe7,0x07,0x00,0x00,0x01,
-   0x00}}, /* 0x6 */
- {{0x64,0x4f,0x4f,0x88,0x55,0x9d,0xf2,0x1f,
-   0xe0,0x83,0xdf,0xdf,0xf3,0x10,0x00,0x01,
-   0x00}}, /* 0x7 */
- {{0x63,0x4f,0x4f,0x87,0x5a,0x81,0xfb,0x1f,
-   0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05,
-   0x00}}, /* 0x8 */
- {{0x65,0x4f,0x4f,0x89,0x58,0x80,0xfb,0x1f,
-   0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05,
-   0x61}}, /* 0x9 */
- {{0x65,0x4f,0x4f,0x89,0x58,0x80,0x01,0x3e,
-   0xe0,0x83,0xdf,0xdf,0x02,0x00,0x00,0x05,
-   0x61}}, /* 0xa */
- {{0x67,0x4f,0x4f,0x8b,0x58,0x81,0x0d,0x3e,
-   0xe0,0x83,0xdf,0xdf,0x0e,0x00,0x00,0x05,
-   0x61}}, /* 0xb */
- {{0x65,0x4f,0x4f,0x89,0x57,0x9f,0xfb,0x1f,
-   0xe6,0x8a,0xdf,0xdf,0xfc,0x10,0x00,0x01,
-   0x00}}, /* 0xc */
- {{0x7b,0x63,0x63,0x9f,0x6a,0x93,0x6f,0xf0,
-   0x58,0x8a,0x57,0x57,0x70,0x20,0x00,0x05,
-   0x01}}, /* 0xd */
- {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xf0,
-   0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x06,
-   0x01}}, /* 0xe */
- {{0x7d,0x63,0x63,0x81,0x6e,0x1d,0x98,0xf0,
-   0x7c,0x82,0x57,0x57,0x99,0x00,0x00,0x06,
-   0x01}}, /* 0xf */
- {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xf0,
-   0x58,0x8b,0x57,0x57,0x70,0x20,0x00,0x06,
-   0x01}}, /* 0x10 */
- {{0x7e,0x63,0x63,0x82,0x6b,0x13,0x75,0xf0,
-   0x58,0x8b,0x57,0x57,0x76,0x20,0x00,0x06,
-   0x01}}, /* 0x11 */
- {{0x81,0x63,0x63,0x85,0x6d,0x18,0x7a,0xf0,
-   0x58,0x8b,0x57,0x57,0x7b,0x20,0x00,0x06,
-   0x61}}, /* 0x12 */
- {{0x83,0x63,0x63,0x87,0x6e,0x19,0x81,0xf0,
-   0x58,0x8b,0x57,0x57,0x82,0x20,0x00,0x06,
-   0x61}}, /* 0x13 */
- {{0x85,0x63,0x63,0x89,0x6f,0x1a,0x91,0xf0,
-   0x58,0x8b,0x57,0x57,0x92,0x20,0x00,0x06,
-   0x61}}, /* 0x14 */
- {{0x99,0x7f,0x7f,0x9d,0x84,0x1a,0x96,0x1f,
-   0x7f,0x83,0x7f,0x7f,0x97,0x10,0x00,0x02,
-   0x00}}, /* 0x15 */
- {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
-   0x01}}, /* 0x16 */
- {{0xa1,0x7f,0x7f,0x85,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
-   0x01}}, /* 0x17 */
- {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf5,
-   0x00,0x83,0xff,0xff,0x1f,0x10,0x00,0x02,
-   0x01}}, /* 0x18 */
- {{0xa7,0x7f,0x7f,0x8b,0x89,0x95,0x26,0xf5,
-   0x00,0x83,0xff,0xff,0x27,0x10,0x00,0x02,
-   0x01}}, /* 0x19 */
- {{0xa9,0x7f,0x7f,0x8d,0x8c,0x9a,0x2c,0xf5,
-   0x00,0x83,0xff,0xff,0x2d,0x14,0x00,0x02,
-   0x62}}, /* 0x1a */
- {{0xab,0x7f,0x7f,0x8f,0x8d,0x9b,0x35,0xf5,
-   0x00,0x83,0xff,0xff,0x36,0x14,0x00,0x02,
-   0x62}}, /* 0x1b */
- {{0xcf,0x9f,0x9f,0x93,0xb2,0x01,0x14,0xba,
-   0x00,0x83,0xff,0xff,0x15,0x00,0x00,0x03,
-   0x00}}, /* 0x1c */
- {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0x5a,
-   0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
-   0x01}}, /* 0x1d */
- {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0x5a,
-   0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
-   0x01}}, /* 0x1e */
- {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0x5a,
-   0x00,0x83,0xff,0xff,0x2f,0x09,0x00,0x07,
-   0x01}}, /* 0x1f */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-   0x00}}, /* 0x20 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-   0x00}}, /* 0x21 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-   0x00}}, /* 0x22 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-   0x00}}, /* 0x23 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-   0x00}}, /* 0x24 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-   0x00}}, /* 0x25 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-   0x00}}, /* 0x26 */
- {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
-   0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
-   0x00}}, /* 0x27 */
- {{0x43,0xef,0xef,0x87,0x06,0x00,0xd4,0x1f,
-   0xa0,0x83,0x9f,0x9f,0xd5,0x1f,0x41,0x05,
-   0x63}}, /* 0x28 */
- {{0x45,0xef,0xef,0x89,0x07,0x01,0xd9,0x1f,
-   0xa0,0x83,0x9f,0x9f,0xda,0x1f,0x41,0x05,
-   0x63}}, /* 0x29 */
- {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
-   0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
-   0x00}}, /* 0x2a */
- {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
-   0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
-   0x00}}, /* 0x2b */
- {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
-   0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
-   0x00}}, /* 0x2c */
- {{0x59,0xff,0xff,0x9d,0x17,0x13,0x33,0xba,
-   0x00,0x83,0xff,0xff,0x34,0x0f,0x41,0x05,
-   0x44}}, /* 0x2d */
- {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x38,0xba,
-   0x00,0x83,0xff,0xff,0x39,0x0f,0x41,0x05,
-   0x44}}, /* 0x2e */
- {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x3d,0xba,
-   0x00,0x83,0xff,0xff,0x3e,0x0f,0x41,0x05,
-   0x44}}, /* 0x2f */
- {{0x5d,0xff,0xff,0x81,0x19,0x95,0x41,0xba,
-   0x00,0x84,0xff,0xff,0x42,0x0f,0x41,0x05,
-   0x44}}, /* 0x30 */
- {{0x55,0xff,0xff,0x99,0x0d,0x0c,0x3e,0xba,
-   0x00,0x84,0xff,0xff,0x3f,0x0f,0x41,0x05,
-   0x00}}, /* 0x31 */
- {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xba,
-   0x27,0x8b,0xdf,0xdf,0x73,0x00,0x00,0x06,
-   0x01}}, /* 0x32 */
- {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xba,
-   0x26,0x89,0xdf,0xdf,0x6f,0x00,0x00,0x06,
-   0x01}}, /* 0x33 */
- {{0x7f,0x63,0x63,0x82,0x6b,0x13,0x75,0xba,
-   0x29,0x8c,0xdf,0xdf,0x75,0x00,0x00,0x06,
-   0x01}}, /* 0x34 */
- {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf1,
-   0xaf,0x85,0x3f,0x3f,0x25,0x30,0x00,0x02,
-   0x01}}, /* 0x35 */
- {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf1,
-   0xad,0x81,0x3f,0x3f,0x1f,0x30,0x00,0x02,
-   0x01}}, /* 0x36 */
- {{0xa7,0x7f,0x7f,0x88,0x89,0x95,0x26,0xf1,
-   0xb1,0x85,0x3f,0x3f,0x27,0x30,0x00,0x02,
-   0x01}}, /* 0x37 */
- {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xc4,
-   0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
-   0x01}}, /* 0x38 */
- {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0xd4,
-   0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
-   0x01}}, /* 0x39 */
- {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xd4,
-   0x7d,0x81,0xcf,0xcf,0x2f,0x21,0x00,0x07,
-   0x01}}, /* 0x3a */
- {{0xdc,0x9f,0x9f,0x80,0xaf,0x9d,0xe6,0xff,
-   0xc0,0x83,0xbf,0xbf,0xe7,0x10,0x00,0x07,
-   0x01}}, /* 0x3b */
- {{0x6b,0x59,0x59,0x8f,0x5e,0x8c,0x0b,0x3e,
-   0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05,
-   0x00}}, /* 0x3c */
- {{0x6d,0x59,0x59,0x91,0x60,0x89,0x53,0xf0,
-   0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05,
-   0x41}}, /* 0x3d */
- {{0x86,0x6a,0x6a,0x8a,0x74,0x06,0x8c,0x15,
-   0x4f,0x83,0xef,0xef,0x8d,0x30,0x00,0x02,
-   0x00}}, /* 0x3e */
- {{0x81,0x6a,0x6a,0x85,0x70,0x00,0x0f,0x3e,
-   0xeb,0x8e,0xdf,0xdf,0x10,0x00,0x00,0x02,
-   0x00}}, /* 0x3f */
- {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x1e,0xf1,
-   0xae,0x85,0x57,0x57,0x1f,0x30,0x00,0x02,
-   0x01}},  /* 0x40 */
- {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
-   0x01}},  /* 0x41 */
- {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x20,0xf5,
-   0x03,0x88,0xff,0xff,0x21,0x10,0x00,0x07,
-   0x01}},  /* 0x42 */
- {{0xe6,0xae,0xae,0x8a,0xbd,0x90,0x3d,0x10,
-   0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x00,0x03,
-   0x00}},  /* 0x43 */
- {{0xc3,0x8f,0x8f,0x87,0x9b,0x0b,0x82,0xef,
-   0x60,0x83,0x5f,0x5f,0x83,0x10,0x00,0x07,
-   0x01}},  /* 0x44 */
- {{0x86,0x69,0x69,0x8A,0x74,0x06,0x8C,0x15,
-   0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02,
-   0x00}},  /* 0x45 */
- {{0x83,0x69,0x69,0x87,0x6f,0x1d,0x03,0x3E,
-   0xE5,0x8d,0xDF,0xe4,0x04,0x00,0x00,0x06,
-   0x00}},  /* 0x46 */
- {{0x86,0x6A,0x6A,0x8A,0x74,0x06,0x8C,0x15,
-   0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02,
-   0x00}},  /* 0x47 */
- {{0x81,0x6A,0x6A,0x85,0x70,0x00,0x0F,0x3E,
-   0xEB,0x8E,0xDF,0xDF,0x10,0x00,0x00,0x02,
-   0x00}},  /* 0x48 */
- {{0xdd,0xa9,0xa9,0x81,0xb4,0x97,0x26,0xfd,
-   0x01,0x8d,0xff,0x00,0x27,0x10,0x00,0x03,
-   0x01}},  /* 0x49 */
- {{0xd9,0x8f,0x8f,0x9d,0xba,0x0a,0x8a,0xff,
-   0x60,0x8b,0x5f,0x5f,0x8b,0x10,0x00,0x03,
-   0x01}},  /* 0x4a */
- {{0xea,0xae,0xae,0x8e,0xba,0x82,0x40,0x10,
-   0x1b,0x87,0x19,0x1a,0x41,0x0f,0x00,0x03,
-   0x00}},  /* 0x4b */
- {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0xf1,0xff,
-   0xc0,0x83,0xbf,0xbf,0xf2,0x10,0x00,0x07,
-   0x01}},  /* 0x4c */
- {{0x75,0x5f,0x5f,0x99,0x66,0x90,0x53,0xf0,
-   0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05,
-   0x41}},
- {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e,
-   0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00,
-   0x00}},  /* 0x4e */
- {{0xcd,0x9f,0x9f,0x91,0xab,0x1c,0x3a,0xff,
-   0x20,0x83,0x1f,0x1f,0x3b,0x10,0x00,0x07,
-   0x21}},  /* 0x4f */
- {{0x15,0xd1,0xd1,0x99,0xe2,0x19,0x3d,0x10,
-   0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x01,0x0c,
-   0x20}},  /* 0x50 */
- {{0x0e,0xef,0xef,0x92,0xfe,0x03,0x30,0xf0,
-   0x1e,0x83,0x1b,0x1c,0x31,0x00,0x01,0x00,
-   0x61}},  /* 0x51 */
- {{0x85,0x77,0x77,0x89,0x7d,0x01,0x31,0xf0,
-   0x1e,0x84,0x1b,0x1c,0x32,0x00,0x00,0x02,
-   0x41}},  /* 0x52 */
- {{0x87,0x77,0x77,0x8b,0x81,0x0b,0x68,0xf0,
-   0x5a,0x80,0x57,0x57,0x69,0x00,0x00,0x02,
-   0x01}},  /* 0x53 */
- {{0xcd,0x8f,0x8f,0x91,0x9b,0x1b,0x7a,0xff,
-   0x64,0x8c,0x5f,0x62,0x7b,0x10,0x00,0x07,
-   0x41}}   /* 0x54 */
+static const struct SiS_CRT1Table SiSUSB_CRT1Table[] = {
+	{{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f,
+	  0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x00,
+	  0x00}},		/* 0x0 */
+	{{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e,
+	  0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00,
+	  0x00}},		/* 0x1 */
+	{{0x3d, 0x31, 0x31, 0x81, 0x37, 0x1f, 0x72, 0xf0,
+	  0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x05,
+	  0x01}},		/* 0x2 */
+	{{0x4f, 0x3f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5,
+	  0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x01,
+	  0x01}},		/* 0x3 */
+	{{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
+	  0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x05,
+	  0x00}},		/* 0x4 */
+	{{0x5f, 0x4f, 0x4f, 0x83, 0x55, 0x81, 0x0b, 0x3e,
+	  0xe9, 0x8b, 0xdf, 0xe8, 0x0c, 0x00, 0x00, 0x05,
+	  0x00}},		/* 0x5 */
+	{{0x63, 0x4f, 0x4f, 0x87, 0x56, 0x9b, 0x06, 0x3e,
+	  0xe8, 0x8a, 0xdf, 0xe7, 0x07, 0x00, 0x00, 0x01,
+	  0x00}},		/* 0x6 */
+	{{0x64, 0x4f, 0x4f, 0x88, 0x55, 0x9d, 0xf2, 0x1f,
+	  0xe0, 0x83, 0xdf, 0xdf, 0xf3, 0x10, 0x00, 0x01,
+	  0x00}},		/* 0x7 */
+	{{0x63, 0x4f, 0x4f, 0x87, 0x5a, 0x81, 0xfb, 0x1f,
+	  0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05,
+	  0x00}},		/* 0x8 */
+	{{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0xfb, 0x1f,
+	  0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05,
+	  0x61}},		/* 0x9 */
+	{{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0x01, 0x3e,
+	  0xe0, 0x83, 0xdf, 0xdf, 0x02, 0x00, 0x00, 0x05,
+	  0x61}},		/* 0xa */
+	{{0x67, 0x4f, 0x4f, 0x8b, 0x58, 0x81, 0x0d, 0x3e,
+	  0xe0, 0x83, 0xdf, 0xdf, 0x0e, 0x00, 0x00, 0x05,
+	  0x61}},		/* 0xb */
+	{{0x65, 0x4f, 0x4f, 0x89, 0x57, 0x9f, 0xfb, 0x1f,
+	  0xe6, 0x8a, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x01,
+	  0x00}},		/* 0xc */
+	{{0x7b, 0x63, 0x63, 0x9f, 0x6a, 0x93, 0x6f, 0xf0,
+	  0x58, 0x8a, 0x57, 0x57, 0x70, 0x20, 0x00, 0x05,
+	  0x01}},		/* 0xd */
+	{{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xf0,
+	  0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x06,
+	  0x01}},		/* 0xe */
+	{{0x7d, 0x63, 0x63, 0x81, 0x6e, 0x1d, 0x98, 0xf0,
+	  0x7c, 0x82, 0x57, 0x57, 0x99, 0x00, 0x00, 0x06,
+	  0x01}},		/* 0xf */
+	{{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xf0,
+	  0x58, 0x8b, 0x57, 0x57, 0x70, 0x20, 0x00, 0x06,
+	  0x01}},		/* 0x10 */
+	{{0x7e, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xf0,
+	  0x58, 0x8b, 0x57, 0x57, 0x76, 0x20, 0x00, 0x06,
+	  0x01}},		/* 0x11 */
+	{{0x81, 0x63, 0x63, 0x85, 0x6d, 0x18, 0x7a, 0xf0,
+	  0x58, 0x8b, 0x57, 0x57, 0x7b, 0x20, 0x00, 0x06,
+	  0x61}},		/* 0x12 */
+	{{0x83, 0x63, 0x63, 0x87, 0x6e, 0x19, 0x81, 0xf0,
+	  0x58, 0x8b, 0x57, 0x57, 0x82, 0x20, 0x00, 0x06,
+	  0x61}},		/* 0x13 */
+	{{0x85, 0x63, 0x63, 0x89, 0x6f, 0x1a, 0x91, 0xf0,
+	  0x58, 0x8b, 0x57, 0x57, 0x92, 0x20, 0x00, 0x06,
+	  0x61}},		/* 0x14 */
+	{{0x99, 0x7f, 0x7f, 0x9d, 0x84, 0x1a, 0x96, 0x1f,
+	  0x7f, 0x83, 0x7f, 0x7f, 0x97, 0x10, 0x00, 0x02,
+	  0x00}},		/* 0x15 */
+	{{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5,
+	  0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02,
+	  0x01}},		/* 0x16 */
+	{{0xa1, 0x7f, 0x7f, 0x85, 0x86, 0x97, 0x24, 0xf5,
+	  0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02,
+	  0x01}},		/* 0x17 */
+	{{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf5,
+	  0x00, 0x83, 0xff, 0xff, 0x1f, 0x10, 0x00, 0x02,
+	  0x01}},		/* 0x18 */
+	{{0xa7, 0x7f, 0x7f, 0x8b, 0x89, 0x95, 0x26, 0xf5,
+	  0x00, 0x83, 0xff, 0xff, 0x27, 0x10, 0x00, 0x02,
+	  0x01}},		/* 0x19 */
+	{{0xa9, 0x7f, 0x7f, 0x8d, 0x8c, 0x9a, 0x2c, 0xf5,
+	  0x00, 0x83, 0xff, 0xff, 0x2d, 0x14, 0x00, 0x02,
+	  0x62}},		/* 0x1a */
+	{{0xab, 0x7f, 0x7f, 0x8f, 0x8d, 0x9b, 0x35, 0xf5,
+	  0x00, 0x83, 0xff, 0xff, 0x36, 0x14, 0x00, 0x02,
+	  0x62}},		/* 0x1b */
+	{{0xcf, 0x9f, 0x9f, 0x93, 0xb2, 0x01, 0x14, 0xba,
+	  0x00, 0x83, 0xff, 0xff, 0x15, 0x00, 0x00, 0x03,
+	  0x00}},		/* 0x1c */
+	{{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0x5a,
+	  0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07,
+	  0x01}},		/* 0x1d */
+	{{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0x5a,
+	  0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07,
+	  0x01}},		/* 0x1e */
+	{{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0x5a,
+	  0x00, 0x83, 0xff, 0xff, 0x2f, 0x09, 0x00, 0x07,
+	  0x01}},		/* 0x1f */
+	{{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+	  0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+	  0x00}},		/* 0x20 */
+	{{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+	  0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+	  0x00}},		/* 0x21 */
+	{{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+	  0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+	  0x00}},		/* 0x22 */
+	{{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+	  0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+	  0x00}},		/* 0x23 */
+	{{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+	  0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+	  0x00}},		/* 0x24 */
+	{{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+	  0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+	  0x00}},		/* 0x25 */
+	{{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+	  0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+	  0x00}},		/* 0x26 */
+	{{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f,
+	  0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01,
+	  0x00}},		/* 0x27 */
+	{{0x43, 0xef, 0xef, 0x87, 0x06, 0x00, 0xd4, 0x1f,
+	  0xa0, 0x83, 0x9f, 0x9f, 0xd5, 0x1f, 0x41, 0x05,
+	  0x63}},		/* 0x28 */
+	{{0x45, 0xef, 0xef, 0x89, 0x07, 0x01, 0xd9, 0x1f,
+	  0xa0, 0x83, 0x9f, 0x9f, 0xda, 0x1f, 0x41, 0x05,
+	  0x63}},		/* 0x29 */
+	{{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f,
+	  0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01,
+	  0x00}},		/* 0x2a */
+	{{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f,
+	  0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01,
+	  0x00}},		/* 0x2b */
+	{{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f,
+	  0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01,
+	  0x00}},		/* 0x2c */
+	{{0x59, 0xff, 0xff, 0x9d, 0x17, 0x13, 0x33, 0xba,
+	  0x00, 0x83, 0xff, 0xff, 0x34, 0x0f, 0x41, 0x05,
+	  0x44}},		/* 0x2d */
+	{{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x38, 0xba,
+	  0x00, 0x83, 0xff, 0xff, 0x39, 0x0f, 0x41, 0x05,
+	  0x44}},		/* 0x2e */
+	{{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x3d, 0xba,
+	  0x00, 0x83, 0xff, 0xff, 0x3e, 0x0f, 0x41, 0x05,
+	  0x44}},		/* 0x2f */
+	{{0x5d, 0xff, 0xff, 0x81, 0x19, 0x95, 0x41, 0xba,
+	  0x00, 0x84, 0xff, 0xff, 0x42, 0x0f, 0x41, 0x05,
+	  0x44}},		/* 0x30 */
+	{{0x55, 0xff, 0xff, 0x99, 0x0d, 0x0c, 0x3e, 0xba,
+	  0x00, 0x84, 0xff, 0xff, 0x3f, 0x0f, 0x41, 0x05,
+	  0x00}},		/* 0x31 */
+	{{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xba,
+	  0x27, 0x8b, 0xdf, 0xdf, 0x73, 0x00, 0x00, 0x06,
+	  0x01}},		/* 0x32 */
+	{{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xba,
+	  0x26, 0x89, 0xdf, 0xdf, 0x6f, 0x00, 0x00, 0x06,
+	  0x01}},		/* 0x33 */
+	{{0x7f, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xba,
+	  0x29, 0x8c, 0xdf, 0xdf, 0x75, 0x00, 0x00, 0x06,
+	  0x01}},		/* 0x34 */
+	{{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf1,
+	  0xaf, 0x85, 0x3f, 0x3f, 0x25, 0x30, 0x00, 0x02,
+	  0x01}},		/* 0x35 */
+	{{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf1,
+	  0xad, 0x81, 0x3f, 0x3f, 0x1f, 0x30, 0x00, 0x02,
+	  0x01}},		/* 0x36 */
+	{{0xa7, 0x7f, 0x7f, 0x88, 0x89, 0x95, 0x26, 0xf1,
+	  0xb1, 0x85, 0x3f, 0x3f, 0x27, 0x30, 0x00, 0x02,
+	  0x01}},		/* 0x37 */
+	{{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0xc4,
+	  0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07,
+	  0x01}},		/* 0x38 */
+	{{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0xd4,
+	  0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07,
+	  0x01}},		/* 0x39 */
+	{{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0xd4,
+	  0x7d, 0x81, 0xcf, 0xcf, 0x2f, 0x21, 0x00, 0x07,
+	  0x01}},		/* 0x3a */
+	{{0xdc, 0x9f, 0x9f, 0x80, 0xaf, 0x9d, 0xe6, 0xff,
+	  0xc0, 0x83, 0xbf, 0xbf, 0xe7, 0x10, 0x00, 0x07,
+	  0x01}},		/* 0x3b */
+	{{0x6b, 0x59, 0x59, 0x8f, 0x5e, 0x8c, 0x0b, 0x3e,
+	  0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x05,
+	  0x00}},		/* 0x3c */
+	{{0x6d, 0x59, 0x59, 0x91, 0x60, 0x89, 0x53, 0xf0,
+	  0x41, 0x84, 0x3f, 0x3f, 0x54, 0x00, 0x00, 0x05,
+	  0x41}},		/* 0x3d */
+	{{0x86, 0x6a, 0x6a, 0x8a, 0x74, 0x06, 0x8c, 0x15,
+	  0x4f, 0x83, 0xef, 0xef, 0x8d, 0x30, 0x00, 0x02,
+	  0x00}},		/* 0x3e */
+	{{0x81, 0x6a, 0x6a, 0x85, 0x70, 0x00, 0x0f, 0x3e,
+	  0xeb, 0x8e, 0xdf, 0xdf, 0x10, 0x00, 0x00, 0x02,
+	  0x00}},		/* 0x3f */
+	{{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x1e, 0xf1,
+	  0xae, 0x85, 0x57, 0x57, 0x1f, 0x30, 0x00, 0x02,
+	  0x01}},		/* 0x40 */
+	{{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5,
+	  0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02,
+	  0x01}},		/* 0x41 */
+	{{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x20, 0xf5,
+	  0x03, 0x88, 0xff, 0xff, 0x21, 0x10, 0x00, 0x07,
+	  0x01}},		/* 0x42 */
+	{{0xe6, 0xae, 0xae, 0x8a, 0xbd, 0x90, 0x3d, 0x10,
+	  0x1a, 0x8d, 0x19, 0x19, 0x3e, 0x2f, 0x00, 0x03,
+	  0x00}},		/* 0x43 */
+	{{0xc3, 0x8f, 0x8f, 0x87, 0x9b, 0x0b, 0x82, 0xef,
+	  0x60, 0x83, 0x5f, 0x5f, 0x83, 0x10, 0x00, 0x07,
+	  0x01}},		/* 0x44 */
+	{{0x86, 0x69, 0x69, 0x8A, 0x74, 0x06, 0x8C, 0x15,
+	  0x4F, 0x83, 0xEF, 0xEF, 0x8D, 0x30, 0x00, 0x02,
+	  0x00}},		/* 0x45 */
+	{{0x83, 0x69, 0x69, 0x87, 0x6f, 0x1d, 0x03, 0x3E,
+	  0xE5, 0x8d, 0xDF, 0xe4, 0x04, 0x00, 0x00, 0x06,
+	  0x00}},		/* 0x46 */
+	{{0x86, 0x6A, 0x6A, 0x8A, 0x74, 0x06, 0x8C, 0x15,
+	  0x4F, 0x83, 0xEF, 0xEF, 0x8D, 0x30, 0x00, 0x02,
+	  0x00}},		/* 0x47 */
+	{{0x81, 0x6A, 0x6A, 0x85, 0x70, 0x00, 0x0F, 0x3E,
+	  0xEB, 0x8E, 0xDF, 0xDF, 0x10, 0x00, 0x00, 0x02,
+	  0x00}},		/* 0x48 */
+	{{0xdd, 0xa9, 0xa9, 0x81, 0xb4, 0x97, 0x26, 0xfd,
+	  0x01, 0x8d, 0xff, 0x00, 0x27, 0x10, 0x00, 0x03,
+	  0x01}},		/* 0x49 */
+	{{0xd9, 0x8f, 0x8f, 0x9d, 0xba, 0x0a, 0x8a, 0xff,
+	  0x60, 0x8b, 0x5f, 0x5f, 0x8b, 0x10, 0x00, 0x03,
+	  0x01}},		/* 0x4a */
+	{{0xea, 0xae, 0xae, 0x8e, 0xba, 0x82, 0x40, 0x10,
+	  0x1b, 0x87, 0x19, 0x1a, 0x41, 0x0f, 0x00, 0x03,
+	  0x00}},		/* 0x4b */
+	{{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0xf1, 0xff,
+	  0xc0, 0x83, 0xbf, 0xbf, 0xf2, 0x10, 0x00, 0x07,
+	  0x01}},		/* 0x4c */
+	{{0x75, 0x5f, 0x5f, 0x99, 0x66, 0x90, 0x53, 0xf0,
+	  0x41, 0x84, 0x3f, 0x3f, 0x54, 0x00, 0x00, 0x05,
+	  0x41}},
+	{{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e,
+	  0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00,
+	  0x00}},		/* 0x4e */
+	{{0xcd, 0x9f, 0x9f, 0x91, 0xab, 0x1c, 0x3a, 0xff,
+	  0x20, 0x83, 0x1f, 0x1f, 0x3b, 0x10, 0x00, 0x07,
+	  0x21}},		/* 0x4f */
+	{{0x15, 0xd1, 0xd1, 0x99, 0xe2, 0x19, 0x3d, 0x10,
+	  0x1a, 0x8d, 0x19, 0x19, 0x3e, 0x2f, 0x01, 0x0c,
+	  0x20}},		/* 0x50 */
+	{{0x0e, 0xef, 0xef, 0x92, 0xfe, 0x03, 0x30, 0xf0,
+	  0x1e, 0x83, 0x1b, 0x1c, 0x31, 0x00, 0x01, 0x00,
+	  0x61}},		/* 0x51 */
+	{{0x85, 0x77, 0x77, 0x89, 0x7d, 0x01, 0x31, 0xf0,
+	  0x1e, 0x84, 0x1b, 0x1c, 0x32, 0x00, 0x00, 0x02,
+	  0x41}},		/* 0x52 */
+	{{0x87, 0x77, 0x77, 0x8b, 0x81, 0x0b, 0x68, 0xf0,
+	  0x5a, 0x80, 0x57, 0x57, 0x69, 0x00, 0x00, 0x02,
+	  0x01}},		/* 0x53 */
+	{{0xcd, 0x8f, 0x8f, 0x91, 0x9b, 0x1b, 0x7a, 0xff,
+	  0x64, 0x8c, 0x5f, 0x62, 0x7b, 0x10, 0x00, 0x07,
+	  0x41}}		/* 0x54 */
 };
 
-static const struct SiS_VCLKData SiSUSB_VCLKData[] =
-{
-	{ 0x1b,0xe1, 25}, /* 0x00 */
-	{ 0x4e,0xe4, 28}, /* 0x01 */
-	{ 0x57,0xe4, 31}, /* 0x02 */
-	{ 0xc3,0xc8, 36}, /* 0x03 */
-	{ 0x42,0xe2, 40}, /* 0x04 */
-	{ 0xfe,0xcd, 43}, /* 0x05 */
-	{ 0x5d,0xc4, 44}, /* 0x06 */
-	{ 0x52,0xe2, 49}, /* 0x07 */
-	{ 0x53,0xe2, 50}, /* 0x08 */
-	{ 0x74,0x67, 52}, /* 0x09 */
-	{ 0x6d,0x66, 56}, /* 0x0a */
-	{ 0x5a,0x64, 65}, /* 0x0b */
-	{ 0x46,0x44, 67}, /* 0x0c */
-	{ 0xb1,0x46, 68}, /* 0x0d */
-	{ 0xd3,0x4a, 72}, /* 0x0e */
-	{ 0x29,0x61, 75}, /* 0x0f */
-	{ 0x6e,0x46, 76}, /* 0x10 */
-	{ 0x2b,0x61, 78}, /* 0x11 */
-	{ 0x31,0x42, 79}, /* 0x12 */
-	{ 0xab,0x44, 83}, /* 0x13 */
-	{ 0x46,0x25, 84}, /* 0x14 */
-	{ 0x78,0x29, 86}, /* 0x15 */
-	{ 0x62,0x44, 94}, /* 0x16 */
-	{ 0x2b,0x41,104}, /* 0x17 */
-	{ 0x3a,0x23,105}, /* 0x18 */
-	{ 0x70,0x44,108}, /* 0x19 */
-	{ 0x3c,0x23,109}, /* 0x1a */
-	{ 0x5e,0x43,113}, /* 0x1b */
-	{ 0xbc,0x44,116}, /* 0x1c */
-	{ 0xe0,0x46,132}, /* 0x1d */
-	{ 0x54,0x42,135}, /* 0x1e */
-	{ 0xea,0x2a,139}, /* 0x1f */
-	{ 0x41,0x22,157}, /* 0x20 */
-	{ 0x70,0x24,162}, /* 0x21 */
-	{ 0x30,0x21,175}, /* 0x22 */
-	{ 0x4e,0x22,189}, /* 0x23 */
-	{ 0xde,0x26,194}, /* 0x24 */
-	{ 0x62,0x06,202}, /* 0x25 */
-	{ 0x3f,0x03,229}, /* 0x26 */
-	{ 0xb8,0x06,234}, /* 0x27 */
-	{ 0x34,0x02,253}, /* 0x28 */
-	{ 0x58,0x04,255}, /* 0x29 */
-	{ 0x24,0x01,265}, /* 0x2a */
-	{ 0x9b,0x02,267}, /* 0x2b */
-	{ 0x70,0x05,270}, /* 0x2c */
-	{ 0x25,0x01,272}, /* 0x2d */
-	{ 0x9c,0x02,277}, /* 0x2e */
-	{ 0x27,0x01,286}, /* 0x2f */
-	{ 0x3c,0x02,291}, /* 0x30 */
-	{ 0xef,0x0a,292}, /* 0x31 */
-	{ 0xf6,0x0a,310}, /* 0x32 */
-	{ 0x95,0x01,315}, /* 0x33 */
-	{ 0xf0,0x09,324}, /* 0x34 */
-	{ 0xfe,0x0a,331}, /* 0x35 */
-	{ 0xf3,0x09,332}, /* 0x36 */
-	{ 0xea,0x08,340}, /* 0x37 */
-	{ 0xe8,0x07,376}, /* 0x38 */
-	{ 0xde,0x06,389}, /* 0x39 */
-	{ 0x52,0x2a, 54}, /* 0x3a 301 TV */
-	{ 0x52,0x6a, 27}, /* 0x3b 301 TV */
-	{ 0x62,0x24, 70}, /* 0x3c 301 TV */
-	{ 0x62,0x64, 70}, /* 0x3d 301 TV */
-	{ 0xa8,0x4c, 30}, /* 0x3e 301 TV */
-	{ 0x20,0x26, 33}, /* 0x3f 301 TV */
-	{ 0x31,0xc2, 39}, /* 0x40 */
-	{ 0x60,0x36, 30}, /* 0x41 Chrontel */
-	{ 0x40,0x4a, 28}, /* 0x42 Chrontel */
-	{ 0x9f,0x46, 44}, /* 0x43 Chrontel */
-	{ 0x97,0x2c, 26}, /* 0x44 */
-	{ 0x44,0xe4, 25}, /* 0x45 Chrontel */
-	{ 0x7e,0x32, 47}, /* 0x46 Chrontel */
-	{ 0x8a,0x24, 31}, /* 0x47 Chrontel */
-	{ 0x97,0x2c, 26}, /* 0x48 Chrontel */
-	{ 0xce,0x3c, 39}, /* 0x49 */
-	{ 0x52,0x4a, 36}, /* 0x4a Chrontel */
-	{ 0x34,0x61, 95}, /* 0x4b */
-	{ 0x78,0x27,108}, /* 0x4c - was 102 */
-	{ 0x66,0x43,123}, /* 0x4d Modes 0x26-0x28 (1400x1050) */
-	{ 0x41,0x4e, 21}, /* 0x4e */
-	{ 0xa1,0x4a, 29}, /* 0x4f Chrontel */
-	{ 0x19,0x42, 42}, /* 0x50 */
-	{ 0x54,0x46, 58}, /* 0x51 Chrontel */
-	{ 0x25,0x42, 61}, /* 0x52 */
-	{ 0x44,0x44, 66}, /* 0x53 Chrontel */
-	{ 0x3a,0x62, 70}, /* 0x54 Chrontel */
-	{ 0x62,0xc6, 34}, /* 0x55 848x480-60 */
-	{ 0x6a,0xc6, 37}, /* 0x56 848x480-75 - TEMP */
-	{ 0xbf,0xc8, 35}, /* 0x57 856x480-38i,60 */
-	{ 0x30,0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) */
-	{ 0x52,0x07,149}, /* 0x59 1280x960-85 */
-	{ 0x56,0x07,156}, /* 0x5a 1400x1050-75 */
-	{ 0x70,0x29, 81}, /* 0x5b 1280x768 LCD */
-	{ 0x45,0x25, 83}, /* 0x5c 1280x800  */
-	{ 0x70,0x0a,147}, /* 0x5d 1680x1050 */
-	{ 0x70,0x24,162}, /* 0x5e 1600x1200 */
-	{ 0x5a,0x64, 65}, /* 0x5f 1280x720 - temp */
-	{ 0x63,0x46, 68}, /* 0x60 1280x768_2 */
-	{ 0x31,0x42, 79}, /* 0x61 1280x768_3 - temp */
-	{    0,   0,  0}, /* 0x62 - custom (will be filled out at run-time) */
-	{ 0x5a,0x64, 65}, /* 0x63 1280x720 (LCD LVDS) */
-	{ 0x70,0x28, 90}, /* 0x64 1152x864@60 */
-	{ 0x41,0xc4, 32}, /* 0x65 848x480@60 */
-	{ 0x5c,0xc6, 32}, /* 0x66 856x480@60 */
-	{ 0x76,0xe7, 27}, /* 0x67 720x480@60 */
-	{ 0x5f,0xc6, 33}, /* 0x68 720/768x576@60 */
-	{ 0x52,0x27, 75}, /* 0x69 1920x1080i 60Hz interlaced */
-	{ 0x7c,0x6b, 38}, /* 0x6a 960x540@60 */
-	{ 0xe3,0x56, 41}, /* 0x6b 960x600@60 */
-	{ 0x45,0x25, 83}, /* 0x6c 1280x800 */
-	{ 0x70,0x28, 90}, /* 0x6d 1152x864@60 */
-	{ 0x15,0xe1, 20}, /* 0x6e 640x400@60 (fake, not actually used) */
-	{ 0x5f,0xc6, 33}, /* 0x6f 720x576@60 */
-	{ 0x37,0x5a, 10}, /* 0x70 320x200@60 (fake, not actually used) */
-	{ 0x2b,0xc2, 35}  /* 0x71 768@576@60 */
+static const struct SiS_VCLKData SiSUSB_VCLKData[] = {
+	{0x1b, 0xe1, 25},	/* 0x00 */
+	{0x4e, 0xe4, 28},	/* 0x01 */
+	{0x57, 0xe4, 31},	/* 0x02 */
+	{0xc3, 0xc8, 36},	/* 0x03 */
+	{0x42, 0xe2, 40},	/* 0x04 */
+	{0xfe, 0xcd, 43},	/* 0x05 */
+	{0x5d, 0xc4, 44},	/* 0x06 */
+	{0x52, 0xe2, 49},	/* 0x07 */
+	{0x53, 0xe2, 50},	/* 0x08 */
+	{0x74, 0x67, 52},	/* 0x09 */
+	{0x6d, 0x66, 56},	/* 0x0a */
+	{0x5a, 0x64, 65},	/* 0x0b */
+	{0x46, 0x44, 67},	/* 0x0c */
+	{0xb1, 0x46, 68},	/* 0x0d */
+	{0xd3, 0x4a, 72},	/* 0x0e */
+	{0x29, 0x61, 75},	/* 0x0f */
+	{0x6e, 0x46, 76},	/* 0x10 */
+	{0x2b, 0x61, 78},	/* 0x11 */
+	{0x31, 0x42, 79},	/* 0x12 */
+	{0xab, 0x44, 83},	/* 0x13 */
+	{0x46, 0x25, 84},	/* 0x14 */
+	{0x78, 0x29, 86},	/* 0x15 */
+	{0x62, 0x44, 94},	/* 0x16 */
+	{0x2b, 0x41, 104},	/* 0x17 */
+	{0x3a, 0x23, 105},	/* 0x18 */
+	{0x70, 0x44, 108},	/* 0x19 */
+	{0x3c, 0x23, 109},	/* 0x1a */
+	{0x5e, 0x43, 113},	/* 0x1b */
+	{0xbc, 0x44, 116},	/* 0x1c */
+	{0xe0, 0x46, 132},	/* 0x1d */
+	{0x54, 0x42, 135},	/* 0x1e */
+	{0xea, 0x2a, 139},	/* 0x1f */
+	{0x41, 0x22, 157},	/* 0x20 */
+	{0x70, 0x24, 162},	/* 0x21 */
+	{0x30, 0x21, 175},	/* 0x22 */
+	{0x4e, 0x22, 189},	/* 0x23 */
+	{0xde, 0x26, 194},	/* 0x24 */
+	{0x62, 0x06, 202},	/* 0x25 */
+	{0x3f, 0x03, 229},	/* 0x26 */
+	{0xb8, 0x06, 234},	/* 0x27 */
+	{0x34, 0x02, 253},	/* 0x28 */
+	{0x58, 0x04, 255},	/* 0x29 */
+	{0x24, 0x01, 265},	/* 0x2a */
+	{0x9b, 0x02, 267},	/* 0x2b */
+	{0x70, 0x05, 270},	/* 0x2c */
+	{0x25, 0x01, 272},	/* 0x2d */
+	{0x9c, 0x02, 277},	/* 0x2e */
+	{0x27, 0x01, 286},	/* 0x2f */
+	{0x3c, 0x02, 291},	/* 0x30 */
+	{0xef, 0x0a, 292},	/* 0x31 */
+	{0xf6, 0x0a, 310},	/* 0x32 */
+	{0x95, 0x01, 315},	/* 0x33 */
+	{0xf0, 0x09, 324},	/* 0x34 */
+	{0xfe, 0x0a, 331},	/* 0x35 */
+	{0xf3, 0x09, 332},	/* 0x36 */
+	{0xea, 0x08, 340},	/* 0x37 */
+	{0xe8, 0x07, 376},	/* 0x38 */
+	{0xde, 0x06, 389},	/* 0x39 */
+	{0x52, 0x2a, 54},	/* 0x3a 301 TV */
+	{0x52, 0x6a, 27},	/* 0x3b 301 TV */
+	{0x62, 0x24, 70},	/* 0x3c 301 TV */
+	{0x62, 0x64, 70},	/* 0x3d 301 TV */
+	{0xa8, 0x4c, 30},	/* 0x3e 301 TV */
+	{0x20, 0x26, 33},	/* 0x3f 301 TV */
+	{0x31, 0xc2, 39},	/* 0x40 */
+	{0x60, 0x36, 30},	/* 0x41 Chrontel */
+	{0x40, 0x4a, 28},	/* 0x42 Chrontel */
+	{0x9f, 0x46, 44},	/* 0x43 Chrontel */
+	{0x97, 0x2c, 26},	/* 0x44 */
+	{0x44, 0xe4, 25},	/* 0x45 Chrontel */
+	{0x7e, 0x32, 47},	/* 0x46 Chrontel */
+	{0x8a, 0x24, 31},	/* 0x47 Chrontel */
+	{0x97, 0x2c, 26},	/* 0x48 Chrontel */
+	{0xce, 0x3c, 39},	/* 0x49 */
+	{0x52, 0x4a, 36},	/* 0x4a Chrontel */
+	{0x34, 0x61, 95},	/* 0x4b */
+	{0x78, 0x27, 108},	/* 0x4c - was 102 */
+	{0x66, 0x43, 123},	/* 0x4d Modes 0x26-0x28 (1400x1050) */
+	{0x41, 0x4e, 21},	/* 0x4e */
+	{0xa1, 0x4a, 29},	/* 0x4f Chrontel */
+	{0x19, 0x42, 42},	/* 0x50 */
+	{0x54, 0x46, 58},	/* 0x51 Chrontel */
+	{0x25, 0x42, 61},	/* 0x52 */
+	{0x44, 0x44, 66},	/* 0x53 Chrontel */
+	{0x3a, 0x62, 70},	/* 0x54 Chrontel */
+	{0x62, 0xc6, 34},	/* 0x55 848x480-60 */
+	{0x6a, 0xc6, 37},	/* 0x56 848x480-75 - TEMP */
+	{0xbf, 0xc8, 35},	/* 0x57 856x480-38i,60 */
+	{0x30, 0x23, 88},	/* 0x58 1360x768-62 (is 60Hz!) */
+	{0x52, 0x07, 149},	/* 0x59 1280x960-85 */
+	{0x56, 0x07, 156},	/* 0x5a 1400x1050-75 */
+	{0x70, 0x29, 81},	/* 0x5b 1280x768 LCD */
+	{0x45, 0x25, 83},	/* 0x5c 1280x800  */
+	{0x70, 0x0a, 147},	/* 0x5d 1680x1050 */
+	{0x70, 0x24, 162},	/* 0x5e 1600x1200 */
+	{0x5a, 0x64, 65},	/* 0x5f 1280x720 - temp */
+	{0x63, 0x46, 68},	/* 0x60 1280x768_2 */
+	{0x31, 0x42, 79},	/* 0x61 1280x768_3 - temp */
+	{0, 0, 0},		/* 0x62 - custom (will be filled out at run-time) */
+	{0x5a, 0x64, 65},	/* 0x63 1280x720 (LCD LVDS) */
+	{0x70, 0x28, 90},	/* 0x64 1152x864@60 */
+	{0x41, 0xc4, 32},	/* 0x65 848x480@60 */
+	{0x5c, 0xc6, 32},	/* 0x66 856x480@60 */
+	{0x76, 0xe7, 27},	/* 0x67 720x480@60 */
+	{0x5f, 0xc6, 33},	/* 0x68 720/768x576@60 */
+	{0x52, 0x27, 75},	/* 0x69 1920x1080i 60Hz interlaced */
+	{0x7c, 0x6b, 38},	/* 0x6a 960x540@60 */
+	{0xe3, 0x56, 41},	/* 0x6b 960x600@60 */
+	{0x45, 0x25, 83},	/* 0x6c 1280x800 */
+	{0x70, 0x28, 90},	/* 0x6d 1152x864@60 */
+	{0x15, 0xe1, 20},	/* 0x6e 640x400@60 (fake, not actually used) */
+	{0x5f, 0xc6, 33},	/* 0x6f 720x576@60 */
+	{0x37, 0x5a, 10},	/* 0x70 320x200@60 (fake, not actually used) */
+	{0x2b, 0xc2, 35}	/* 0x71 768@576@60 */
 };
 
-int		SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
-int		SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo);
+int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
+int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo);
 
-extern int	sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data);
-extern int	sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data);
-extern int	sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port,
-					u8 index, u8 data);
-extern int	sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port,
-					u8 index, u8 *data);
-extern int	sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port,
-					u8 idx,	u8 myand, u8 myor);
-extern int	sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port,
-					u8 index, u8 myor);
-extern int	sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port,
-					u8 idx, u8 myand);
+extern int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data);
+extern int sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 * data);
+extern int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port,
+			    u8 index, u8 data);
+extern int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port,
+			    u8 index, u8 * data);
+extern int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port,
+				 u8 idx, u8 myand, u8 myor);
+extern int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port,
+			      u8 index, u8 myor);
+extern int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port,
+			       u8 idx, u8 myand);
 
 void sisusb_delete(struct kref *kref);
 int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data);
-int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data);
+int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 * data);
 int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
-		       u32 dest, int length, size_t *bytes_written);
+		       u32 dest, int length, size_t * bytes_written);
 int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init);
 int sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot,
-			 u8 *arg, int cmapsz, int ch512, int dorecalc,
+			 u8 * arg, int cmapsz, int ch512, int dorecalc,
 			 struct vc_data *c, int fh, int uplock);
 void sisusb_set_cursor(struct sisusb_usb_data *sisusb, unsigned int location);
 int sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last);
@@ -839,4 +839,3 @@
 void sisusb_init_concode(void);
 
 #endif
-
diff --git a/drivers/usb/misc/sisusbvga/sisusb_struct.h b/drivers/usb/misc/sisusbvga/sisusb_struct.h
index f325ecb..1c4240e 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_struct.h
+++ b/drivers/usb/misc/sisusbvga/sisusb_struct.h
@@ -44,7 +44,7 @@
  * * (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>
+ * Author:	Thomas Winischhofer <thomas@winischhofer.net>
  *
  */
 
@@ -52,85 +52,78 @@
 #define _SISUSB_STRUCT_H_
 
 struct SiS_St {
-	unsigned char	St_ModeID;
-	unsigned short	St_ModeFlag;
-	unsigned char	St_StTableIndex;
-	unsigned char	St_CRT2CRTC;
-	unsigned char	St_ResInfo;
-	unsigned char	VB_StTVFlickerIndex;
-	unsigned char	VB_StTVEdgeIndex;
-	unsigned char	VB_StTVYFilterIndex;
-	unsigned char	St_PDC;
+	unsigned char St_ModeID;
+	unsigned short St_ModeFlag;
+	unsigned char St_StTableIndex;
+	unsigned char St_CRT2CRTC;
+	unsigned char St_ResInfo;
+	unsigned char VB_StTVFlickerIndex;
+	unsigned char VB_StTVEdgeIndex;
+	unsigned char VB_StTVYFilterIndex;
+	unsigned char St_PDC;
 };
 
-struct SiS_StandTable
-{
-	unsigned char	CRT_COLS;
-	unsigned char	ROWS;
-	unsigned char	CHAR_HEIGHT;
-	unsigned short	CRT_LEN;
-	unsigned char	SR[4];
-	unsigned char	MISC;
-	unsigned char	CRTC[0x19];
-	unsigned char	ATTR[0x14];
-	unsigned char	GRC[9];
+struct SiS_StandTable {
+	unsigned char CRT_COLS;
+	unsigned char ROWS;
+	unsigned char CHAR_HEIGHT;
+	unsigned short CRT_LEN;
+	unsigned char SR[4];
+	unsigned char MISC;
+	unsigned char CRTC[0x19];
+	unsigned char ATTR[0x14];
+	unsigned char GRC[9];
 };
 
 struct SiS_StResInfo_S {
-	unsigned short	HTotal;
-	unsigned short	VTotal;
+	unsigned short HTotal;
+	unsigned short VTotal;
 };
 
-struct SiS_Ext
-{
-	unsigned char	Ext_ModeID;
-	unsigned short	Ext_ModeFlag;
-	unsigned short	Ext_VESAID;
-	unsigned char	Ext_RESINFO;
-	unsigned char	VB_ExtTVFlickerIndex;
-	unsigned char	VB_ExtTVEdgeIndex;
-	unsigned char	VB_ExtTVYFilterIndex;
-	unsigned char	VB_ExtTVYFilterIndexROM661;
-	unsigned char	REFindex;
-	char		ROMMODEIDX661;
+struct SiS_Ext {
+	unsigned char Ext_ModeID;
+	unsigned short Ext_ModeFlag;
+	unsigned short Ext_VESAID;
+	unsigned char Ext_RESINFO;
+	unsigned char VB_ExtTVFlickerIndex;
+	unsigned char VB_ExtTVEdgeIndex;
+	unsigned char VB_ExtTVYFilterIndex;
+	unsigned char VB_ExtTVYFilterIndexROM661;
+	unsigned char REFindex;
+	char ROMMODEIDX661;
 };
 
-struct SiS_Ext2
-{
-	unsigned short	Ext_InfoFlag;
-	unsigned char	Ext_CRT1CRTC;
-	unsigned char	Ext_CRTVCLK;
-	unsigned char	Ext_CRT2CRTC;
-	unsigned char	Ext_CRT2CRTC_NS;
-	unsigned char	ModeID;
-	unsigned short	XRes;
-	unsigned short	YRes;
-	unsigned char	Ext_PDC;
-	unsigned char	Ext_FakeCRT2CRTC;
-	unsigned char	Ext_FakeCRT2Clk;
+struct SiS_Ext2 {
+	unsigned short Ext_InfoFlag;
+	unsigned char Ext_CRT1CRTC;
+	unsigned char Ext_CRTVCLK;
+	unsigned char Ext_CRT2CRTC;
+	unsigned char Ext_CRT2CRTC_NS;
+	unsigned char ModeID;
+	unsigned short XRes;
+	unsigned short YRes;
+	unsigned char Ext_PDC;
+	unsigned char Ext_FakeCRT2CRTC;
+	unsigned char Ext_FakeCRT2Clk;
 };
 
-struct SiS_CRT1Table
-{
-	unsigned char	CR[17];
+struct SiS_CRT1Table {
+	unsigned char CR[17];
 };
 
-struct SiS_VCLKData
-{
-	unsigned char	SR2B,SR2C;
-	unsigned short	CLOCK;
+struct SiS_VCLKData {
+	unsigned char SR2B, SR2C;
+	unsigned short CLOCK;
 };
 
-struct SiS_ModeResInfo
-{
-	unsigned short	HTotal;
-	unsigned short	VTotal;
-	unsigned char	XChar;
-	unsigned char	YChar;
+struct SiS_ModeResInfo {
+	unsigned short HTotal;
+	unsigned short VTotal;
+	unsigned char XChar;
+	unsigned char YChar;
 };
 
-struct SiS_Private
-{
+struct SiS_Private {
 	void *sisusb;
 
 	unsigned long IOAddress;
@@ -151,19 +144,18 @@
 	unsigned long SiS_P3da;
 	unsigned long SiS_Part1Port;
 
-	unsigned char	SiS_MyCR63;
-	unsigned short	SiS_CRT1Mode;
-	unsigned short	SiS_ModeType;
-	unsigned short	SiS_SetFlag;
+	unsigned char SiS_MyCR63;
+	unsigned short SiS_CRT1Mode;
+	unsigned short SiS_ModeType;
+	unsigned short SiS_SetFlag;
 
-	const struct SiS_StandTable	*SiS_StandTable;
-	const struct SiS_St		*SiS_SModeIDTable;
-	const struct SiS_Ext		*SiS_EModeIDTable;
-	const struct SiS_Ext2		*SiS_RefIndex;
-	const struct SiS_CRT1Table	*SiS_CRT1Table;
-	const struct SiS_VCLKData	*SiS_VCLKData;
-	const struct SiS_ModeResInfo	*SiS_ModeResInfo;
+	const struct SiS_StandTable *SiS_StandTable;
+	const struct SiS_St *SiS_SModeIDTable;
+	const struct SiS_Ext *SiS_EModeIDTable;
+	const struct SiS_Ext2 *SiS_RefIndex;
+	const struct SiS_CRT1Table *SiS_CRT1Table;
+	const struct SiS_VCLKData *SiS_VCLKData;
+	const struct SiS_ModeResInfo *SiS_ModeResInfo;
 };
 
 #endif
-
diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c
index c03dfd7..f06e4e2 100644
--- a/drivers/usb/mon/mon_bin.c
+++ b/drivers/usb/mon/mon_bin.c
@@ -172,6 +172,10 @@
 
 #define MON_RING_EMPTY(rp)	((rp)->b_cnt == 0)
 
+static unsigned char xfer_to_pipe[4] = {
+	PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT
+};
+
 static struct class *mon_bin_class;
 static dev_t mon_bin_dev0;
 static struct cdev mon_bin_cdev;
@@ -354,13 +358,9 @@
     const struct urb *urb, char ev_type)
 {
 
-	if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
+	if (!usb_endpoint_xfer_control(&urb->ep->desc) || ev_type != 'S')
 		return '-';
 
-	if (urb->dev->bus->uses_dma &&
-	    (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
-		return mon_dmapeek(setupb, urb->setup_dma, SETUP_LEN);
-	}
 	if (urb->setup_packet == NULL)
 		return 'Z';
 
@@ -386,13 +386,15 @@
 }
 
 static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
-    char ev_type)
+    char ev_type, int status)
 {
+	const struct usb_endpoint_descriptor *epd = &urb->ep->desc;
 	unsigned long flags;
 	struct timeval ts;
 	unsigned int urb_length;
 	unsigned int offset;
 	unsigned int length;
+	unsigned char dir;
 	struct mon_bin_hdr *ep;
 	char data_tag = 0;
 
@@ -410,16 +412,19 @@
 	if (length >= rp->b_size/5)
 		length = rp->b_size/5;
 
-	if (usb_pipein(urb->pipe)) {
+	if (usb_urb_dir_in(urb)) {
 		if (ev_type == 'S') {
 			length = 0;
 			data_tag = '<';
 		}
+		/* Cannot rely on endpoint number in case of control ep.0 */
+		dir = USB_DIR_IN;
 	} else {
 		if (ev_type == 'C') {
 			length = 0;
 			data_tag = '>';
 		}
+		dir = 0;
 	}
 
 	if (rp->mmap_active)
@@ -440,15 +445,14 @@
 	 */
 	memset(ep, 0, PKT_SIZE);
 	ep->type = ev_type;
-	ep->xfer_type = usb_pipetype(urb->pipe);
-	/* We use the fact that usb_pipein() returns 0x80 */
-	ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
-	ep->devnum = usb_pipedevice(urb->pipe);
+	ep->xfer_type = xfer_to_pipe[usb_endpoint_type(epd)];
+	ep->epnum = dir | usb_endpoint_num(epd);
+	ep->devnum = urb->dev->devnum;
 	ep->busnum = urb->dev->bus->busnum;
 	ep->id = (unsigned long) urb;
 	ep->ts_sec = ts.tv_sec;
 	ep->ts_usec = ts.tv_usec;
-	ep->status = urb->status;
+	ep->status = status;
 	ep->len_urb = urb_length;
 	ep->len_cap = length;
 
@@ -471,13 +475,13 @@
 static void mon_bin_submit(void *data, struct urb *urb)
 {
 	struct mon_reader_bin *rp = data;
-	mon_bin_event(rp, urb, 'S');
+	mon_bin_event(rp, urb, 'S', -EINPROGRESS);
 }
 
-static void mon_bin_complete(void *data, struct urb *urb)
+static void mon_bin_complete(void *data, struct urb *urb, int status)
 {
 	struct mon_reader_bin *rp = data;
-	mon_bin_event(rp, urb, 'C');
+	mon_bin_event(rp, urb, 'C', status);
 }
 
 static void mon_bin_error(void *data, struct urb *urb, int error)
@@ -500,10 +504,10 @@
 
 	memset(ep, 0, PKT_SIZE);
 	ep->type = 'E';
-	ep->xfer_type = usb_pipetype(urb->pipe);
-	/* We use the fact that usb_pipein() returns 0x80 */
-	ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
-	ep->devnum = usb_pipedevice(urb->pipe);
+	ep->xfer_type = xfer_to_pipe[usb_endpoint_type(&urb->ep->desc)];
+	ep->epnum = usb_urb_dir_in(urb) ? USB_DIR_IN : 0;
+	ep->epnum |= usb_endpoint_num(&urb->ep->desc);
+	ep->devnum = urb->dev->devnum;
 	ep->busnum = urb->dev->bus->busnum;
 	ep->id = (unsigned long) urb;
 	ep->status = error;
diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c
index ce61d8b..b371ffd 100644
--- a/drivers/usb/mon/mon_main.c
+++ b/drivers/usb/mon/mon_main.c
@@ -129,7 +129,8 @@
 
 /*
  */
-static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb)
+static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb,
+		int status)
 {
 	unsigned long flags;
 	struct list_head *pos;
@@ -139,28 +140,18 @@
 	mbus->cnt_events++;
 	list_for_each (pos, &mbus->r_list) {
 		r = list_entry(pos, struct mon_reader, r_link);
-		r->rnf_complete(r->r_data, urb);
+		r->rnf_complete(r->r_data, urb, status);
 	}
 	spin_unlock_irqrestore(&mbus->lock, flags);
 }
 
-static void mon_complete(struct usb_bus *ubus, struct urb *urb)
+static void mon_complete(struct usb_bus *ubus, struct urb *urb, int status)
 {
 	struct mon_bus *mbus;
 
-	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;
-	}
-
-	mon_bus_complete(mbus, urb);
-	mon_bus_complete(&mon_bus0, urb);
+	if ((mbus = ubus->mon_bus) != NULL)
+		mon_bus_complete(mbus, urb, status);
+	mon_bus_complete(&mon_bus0, urb, status);
 }
 
 /* int (*unlink_urb) (struct urb *urb, int status); */
@@ -170,7 +161,7 @@
  */
 static void mon_stop(struct mon_bus *mbus)
 {
-	struct usb_bus *ubus = mbus->u_bus;
+	struct usb_bus *ubus;
 	struct list_head *p;
 
 	if (mbus == &mon_bus0) {
diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c
index 8f27a9e..ebb04ac 100644
--- a/drivers/usb/mon/mon_text.c
+++ b/drivers/usb/mon/mon_text.c
@@ -50,10 +50,13 @@
 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 busnum;
+	char devnum;
+	char epnum;
+	char is_in;
+	char xfertype;
 	int length;		/* Depends on type: xfer length or act length */
 	int status;
 	int interval;
@@ -121,13 +124,9 @@
     struct urb *urb, char ev_type, struct mon_bus *mbus)
 {
 
-	if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
+	if (ep->xfertype != USB_ENDPOINT_XFER_CONTROL || ev_type != 'S')
 		return '-';
 
-	if (urb->dev->bus->uses_dma &&
-	    (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
-		return mon_dmapeek(ep->setup, urb->setup_dma, SETUP_MAX);
-	}
 	if (urb->setup_packet == NULL)
 		return 'Z';	/* '0' would be not as pretty. */
 
@@ -138,14 +137,12 @@
 static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb,
     int len, char ev_type, struct mon_bus *mbus)
 {
-	int pipe = urb->pipe;
-
 	if (len <= 0)
 		return 'L';
 	if (len >= DATA_MAX)
 		len = DATA_MAX;
 
-	if (usb_pipein(pipe)) {
+	if (ep->is_in) {
 		if (ev_type != 'C')
 			return '<';
 	} else {
@@ -186,7 +183,7 @@
 }
 
 static void mon_text_event(struct mon_reader_text *rp, struct urb *urb,
-    char ev_type)
+    char ev_type, int status)
 {
 	struct mon_event_text *ep;
 	unsigned int stamp;
@@ -203,24 +200,28 @@
 	}
 
 	ep->type = ev_type;
-	ep->pipe = urb->pipe;
 	ep->id = (unsigned long) urb;
 	ep->busnum = urb->dev->bus->busnum;
+	ep->devnum = urb->dev->devnum;
+	ep->epnum = usb_endpoint_num(&urb->ep->desc);
+	ep->xfertype = usb_endpoint_type(&urb->ep->desc);
+	ep->is_in = usb_urb_dir_in(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->status = status;
 
-	if (usb_pipeint(urb->pipe)) {
+	if (ep->xfertype == USB_ENDPOINT_XFER_INT) {
 		ep->interval = urb->interval;
-	} else if (usb_pipeisoc(urb->pipe)) {
+	} else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) {
 		ep->interval = urb->interval;
 		ep->start_frame = urb->start_frame;
 		ep->error_count = urb->error_count;
 	}
 	ep->numdesc = urb->number_of_packets;
-	if (usb_pipeisoc(urb->pipe) && urb->number_of_packets > 0) {
+	if (ep->xfertype == USB_ENDPOINT_XFER_ISOC &&
+			urb->number_of_packets > 0) {
 		if ((ndesc = urb->number_of_packets) > ISODESC_MAX)
 			ndesc = ISODESC_MAX;
 		fp = urb->iso_frame_desc;
@@ -247,13 +248,13 @@
 static void mon_text_submit(void *data, struct urb *urb)
 {
 	struct mon_reader_text *rp = data;
-	mon_text_event(rp, urb, 'S');
+	mon_text_event(rp, urb, 'S', -EINPROGRESS);
 }
 
-static void mon_text_complete(void *data, struct urb *urb)
+static void mon_text_complete(void *data, struct urb *urb, int status)
 {
 	struct mon_reader_text *rp = data;
-	mon_text_event(rp, urb, 'C');
+	mon_text_event(rp, urb, 'C', status);
 }
 
 static void mon_text_error(void *data, struct urb *urb, int error)
@@ -268,9 +269,12 @@
 	}
 
 	ep->type = 'E';
-	ep->pipe = urb->pipe;
 	ep->id = (unsigned long) urb;
 	ep->busnum = 0;
+	ep->devnum = urb->dev->devnum;
+	ep->epnum = usb_endpoint_num(&urb->ep->desc);
+	ep->xfertype = usb_endpoint_type(&urb->ep->desc);
+	ep->is_in = usb_urb_dir_in(urb);
 	ep->tstamp = 0;
 	ep->length = 0;
 	ep->status = error;
@@ -413,10 +417,10 @@
 	mon_text_read_head_u(rp, &ptr, ep);
 	if (ep->type == 'E') {
 		mon_text_read_statset(rp, &ptr, ep);
-	} else if (usb_pipeisoc(ep->pipe)) {
+	} else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) {
 		mon_text_read_isostat(rp, &ptr, ep);
 		mon_text_read_isodesc(rp, &ptr, ep);
-	} else if (usb_pipeint(ep->pipe)) {
+	} else if (ep->xfertype == USB_ENDPOINT_XFER_INT) {
 		mon_text_read_intstat(rp, &ptr, ep);
 	} else {
 		mon_text_read_statset(rp, &ptr, ep);
@@ -468,18 +472,17 @@
 {
 	char udir, utype;
 
-	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;
+	udir = (ep->is_in ? 'i' : 'o');
+	switch (ep->xfertype) {
+	case USB_ENDPOINT_XFER_ISOC:	utype = 'Z'; break;
+	case USB_ENDPOINT_XFER_INT:	utype = 'I'; break;
+	case USB_ENDPOINT_XFER_CONTROL:	utype = 'C'; break;
 	default: /* PIPE_BULK */  utype = 'B';
 	}
 	p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
 	    "%lx %u %c %c%c:%03u:%02u",
 	    ep->id, ep->tstamp, ep->type,
-	    utype, udir,
-	    usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe));
+	    utype, udir, ep->devnum, ep->epnum);
 }
 
 static void mon_text_read_head_u(struct mon_reader_text *rp,
@@ -487,18 +490,17 @@
 {
 	char udir, utype;
 
-	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;
+	udir = (ep->is_in ? 'i' : 'o');
+	switch (ep->xfertype) {
+	case USB_ENDPOINT_XFER_ISOC:	utype = 'Z'; break;
+	case USB_ENDPOINT_XFER_INT:	utype = 'I'; break;
+	case USB_ENDPOINT_XFER_CONTROL:	utype = 'C'; break;
 	default: /* PIPE_BULK */  utype = 'B';
 	}
 	p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
 	    "%lx %u %c %c%c:%d:%03u:%u",
 	    ep->id, ep->tstamp, ep->type,
-	    utype, udir,
-	    ep->busnum, usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe));
+	    utype, udir, ep->busnum, ep->devnum, ep->epnum);
 }
 
 static void mon_text_read_statset(struct mon_reader_text *rp,
diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h
index f68ad6d..f5d84ff 100644
--- a/drivers/usb/mon/usb_mon.h
+++ b/drivers/usb/mon/usb_mon.h
@@ -46,7 +46,7 @@
 
 	void (*rnf_submit)(void *data, struct urb *urb);
 	void (*rnf_error)(void *data, struct urb *urb, int error);
-	void (*rnf_complete)(void *data, struct urb *urb);
+	void (*rnf_complete)(void *data, struct urb *urb, int status);
 };
 
 void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r);
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 43d6db6..99fefed 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -92,6 +92,16 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called belkin_sa.
 
+config USB_SERIAL_CH341
+	tristate "USB Winchiphead CH341 Single Port Serial Driver"
+	depends on USB_SERIAL
+	help
+	  Say Y here if you want to use a Winchiphead CH341 single port
+	  USB to serial adapter.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ch341.
+
 config USB_SERIAL_WHITEHEAT
 	tristate "USB ConnectTech WhiteHEAT Serial Driver"
 	depends on USB_SERIAL
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 07a976e..d6fb384 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -15,6 +15,7 @@
 obj-$(CONFIG_USB_SERIAL_AIRPRIME)		+= airprime.o
 obj-$(CONFIG_USB_SERIAL_ARK3116)		+= ark3116.o
 obj-$(CONFIG_USB_SERIAL_BELKIN)			+= belkin_sa.o
+obj-$(CONFIG_USB_SERIAL_CH341)			+= ch341.o
 obj-$(CONFIG_USB_SERIAL_CP2101)			+= cp2101.o
 obj-$(CONFIG_USB_SERIAL_CYBERJACK)		+= cyberjack.o
 obj-$(CONFIG_USB_SERIAL_CYPRESS_M8)		+= cypress_m8.o
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index c9fd486..2a8e537 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -172,11 +172,6 @@
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
-	if (!port->tty || !port->tty->termios) {
-		dbg("%s - no tty structures", __FUNCTION__);
-		return;
-	}
-
 	spin_lock_irqsave(&priv->lock, flags);
 	if (!priv->termios_initialized) {
 		*(port->tty->termios) = tty_std_termios;
diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c
index a47a24f..0b14aea 100644
--- a/drivers/usb/serial/bus.c
+++ b/drivers/usb/serial/bus.c
@@ -36,6 +36,16 @@
 	return 0;
 }
 
+static ssize_t show_port_number(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct usb_serial_port *port = to_usb_serial_port(dev);
+
+	return sprintf(buf, "%d\n", port->number - port->serial->minor);
+}
+
+static DEVICE_ATTR(port_number, S_IRUGO, show_port_number, NULL);
+
 static int usb_serial_device_probe (struct device *dev)
 {
 	struct usb_serial_driver *driver;
@@ -62,6 +72,10 @@
 			goto exit;
 	}
 
+	retval = device_create_file(dev, &dev_attr_port_number);
+	if (retval)
+		goto exit;
+
 	minor = port->number;
 	tty_register_device (usb_serial_tty_driver, minor, dev);
 	dev_info(&port->serial->dev->dev, 
@@ -84,6 +98,8 @@
 		return -ENODEV;
 	}
 
+	device_remove_file(&port->dev, &dev_attr_port_number);
+
 	driver = port->serial->type;
 	if (driver->port_remove) {
 		if (!try_module_get(driver->driver.owner)) {
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
new file mode 100644
index 0000000..6b252ce
--- /dev/null
+++ b/drivers/usb/serial/ch341.c
@@ -0,0 +1,354 @@
+/*
+ * Copyright 2007, Frank A Kingswood <frank@kingswood-consulting.co.uk>
+ *
+ * ch341.c implements a serial port driver for the Winchiphead CH341.
+ *
+ * The CH341 device can be used to implement an RS232 asynchronous
+ * serial port, an IEEE-1284 parallel printer port or a memory-like
+ * interface. In all cases the CH341 supports an I2C interface as well.
+ * This driver only supports the asynchronous serial interface.
+ *
+ * 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 <linux/usb/serial.h>
+#include <linux/serial.h>
+
+#define DEFAULT_BAUD_RATE 2400
+#define DEFAULT_TIMEOUT   1000
+
+static int debug;
+
+static struct usb_device_id id_table [] = {
+	{ USB_DEVICE(0x4348, 0x5523) },
+	{ },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+struct ch341_private {
+	unsigned baud_rate;
+	u8 dtr;
+	u8 rts;
+};
+
+static int ch341_control_out(struct usb_device *dev, u8 request,
+			     u16 value, u16 index)
+{
+	int r;
+	dbg("ch341_control_out(%02x,%02x,%04x,%04x)", USB_DIR_OUT|0x40,
+		(int)request, (int)value, (int)index);
+
+	r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request,
+			    USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+			    value, index, NULL, 0, DEFAULT_TIMEOUT);
+
+	return r;
+}
+
+static int ch341_control_in(struct usb_device *dev,
+			    u8 request, u16 value, u16 index,
+			    char *buf, unsigned bufsize)
+{
+	int r;
+	dbg("ch341_control_in(%02x,%02x,%04x,%04x,%p,%u)", USB_DIR_IN|0x40,
+		(int)request, (int)value, (int)index, buf, (int)bufsize);
+
+	r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request,
+			    USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+			    value, index, buf, bufsize, DEFAULT_TIMEOUT);
+	return r;
+}
+
+static int ch341_set_baudrate(struct usb_device *dev,
+			      struct ch341_private *priv)
+{
+	short a, b;
+	int r;
+
+	dbg("ch341_set_baudrate(%d)", priv->baud_rate);
+	switch (priv->baud_rate) {
+	case 2400:
+		a = 0xd901;
+		b = 0x0038;
+		break;
+	case 4800:
+		a = 0x6402;
+		b = 0x001f;
+		break;
+	case 9600:
+		a = 0xb202;
+		b = 0x0013;
+		break;
+	case 19200:
+		a = 0xd902;
+		b = 0x000d;
+		break;
+	case 38400:
+		a = 0x6403;
+		b = 0x000a;
+		break;
+	case 115200:
+		a = 0xcc03;
+		b = 0x0008;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	r = ch341_control_out(dev, 0x9a, 0x1312, a);
+	if (!r)
+		r = ch341_control_out(dev, 0x9a, 0x0f2c, b);
+
+	return r;
+}
+
+static int ch341_set_handshake(struct usb_device *dev,
+			       struct ch341_private *priv)
+{
+	dbg("ch341_set_handshake(%d,%d)", priv->dtr, priv->rts);
+	return ch341_control_out(dev, 0xa4,
+		~((priv->dtr?1<<5:0)|(priv->rts?1<<6:0)), 0);
+}
+
+static int ch341_get_status(struct usb_device *dev)
+{
+	char *buffer;
+	int r;
+	const unsigned size = 8;
+
+	dbg("ch341_get_status()");
+
+	buffer = kmalloc(size, GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+
+	r = ch341_control_in(dev, 0x95, 0x0706, 0, buffer, size);
+	if ( r < 0)
+		goto out;
+
+	/* Not having the datasheet for the CH341, we ignore the bytes returned
+	 * from the device. Return error if the device did not respond in time.
+	 */
+	r = 0;
+
+out:	kfree(buffer);
+	return r;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int ch341_configure(struct usb_device *dev, struct ch341_private *priv)
+{
+	char *buffer;
+	int r;
+	const unsigned size = 8;
+
+	dbg("ch341_configure()");
+
+	buffer = kmalloc(size, GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+
+	/* expect two bytes 0x27 0x00 */
+	r = ch341_control_in(dev, 0x5f, 0, 0, buffer, size);
+	if (r < 0)
+		goto out;
+
+	r = ch341_control_out(dev, 0xa1, 0, 0);
+	if (r < 0)
+		goto out;
+
+	r = ch341_set_baudrate(dev, priv);
+	if (r < 0)
+		goto out;
+
+	/* expect two bytes 0x56 0x00 */
+	r = ch341_control_in(dev, 0x95, 0x2518, 0, buffer, size);
+	if (r < 0)
+		goto out;
+
+	r = ch341_control_out(dev, 0x9a, 0x2518, 0x0050);
+	if (r < 0)
+		goto out;
+
+	/* expect 0xff 0xee */
+	r = ch341_get_status(dev);
+	if (r < 0)
+		goto out;
+
+	r = ch341_control_out(dev, 0xa1, 0x501f, 0xd90a);
+	if (r < 0)
+		goto out;
+
+	r = ch341_set_baudrate(dev, priv);
+	if (r < 0)
+		goto out;
+
+	r = ch341_set_handshake(dev, priv);
+	if (r < 0)
+		goto out;
+
+	/* expect 0x9f 0xee */
+	r = ch341_get_status(dev);
+
+out:	kfree(buffer);
+	return r;
+}
+
+/* allocate private data */
+static int ch341_attach(struct usb_serial *serial)
+{
+	struct ch341_private *priv;
+	int r;
+
+	dbg("ch341_attach()");
+
+	/* private data */
+	priv = kzalloc(sizeof(struct ch341_private), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->baud_rate = DEFAULT_BAUD_RATE;
+	priv->dtr = 1;
+	priv->rts = 1;
+
+	r = ch341_configure(serial->dev, priv);
+	if (r < 0)
+		goto error;
+
+	usb_set_serial_port_data(serial->port[0], priv);
+	return 0;
+
+error:	kfree(priv);
+	return r;
+}
+
+/* open this device, set default parameters */
+static int ch341_open(struct usb_serial_port *port, struct file *filp)
+{
+	struct usb_serial *serial = port->serial;
+	struct ch341_private *priv = usb_get_serial_port_data(serial->port[0]);
+	int r;
+
+	dbg("ch341_open()");
+
+	priv->baud_rate = DEFAULT_BAUD_RATE;
+	priv->dtr = 1;
+	priv->rts = 1;
+
+	r = ch341_configure(serial->dev, priv);
+	if (r)
+		goto out;
+
+	r = ch341_set_handshake(serial->dev, priv);
+	if (r)
+		goto out;
+
+	r = ch341_set_baudrate(serial->dev, priv);
+	if (r)
+		goto out;
+
+	r = usb_serial_generic_open(port, filp);
+
+out:	return r;
+}
+
+/* Old_termios contains the original termios settings and
+ * tty->termios contains the new setting to be used.
+ */
+static void ch341_set_termios(struct usb_serial_port *port,
+			      struct ktermios *old_termios)
+{
+	struct ch341_private *priv = usb_get_serial_port_data(port);
+	struct tty_struct *tty = port->tty;
+	unsigned baud_rate;
+
+	dbg("ch341_set_termios()");
+
+	if (!tty || !tty->termios)
+		return;
+
+	baud_rate = tty_get_baud_rate(tty);
+
+	switch (baud_rate) {
+	case 2400:
+	case 4800:
+	case 9600:
+	case 19200:
+	case 38400:
+	case 115200:
+		priv->baud_rate = baud_rate;
+		break;
+	default:
+		dbg("Rate %d not supported, using %d",
+			baud_rate, DEFAULT_BAUD_RATE);
+		priv->baud_rate = DEFAULT_BAUD_RATE;
+	}
+
+	ch341_set_baudrate(port->serial->dev, priv);
+
+	/* Unimplemented:
+	 * (cflag & CSIZE) : data bits [5, 8]
+	 * (cflag & PARENB) : parity {NONE, EVEN, ODD}
+	 * (cflag & CSTOPB) : stop bits [1, 2]
+	 */
+}
+
+static struct usb_driver ch341_driver = {
+	.name		= "ch341",
+	.probe		= usb_serial_probe,
+	.disconnect	= usb_serial_disconnect,
+	.id_table	= id_table,
+	.no_dynamic_id	= 1,
+};
+
+static struct usb_serial_driver ch341_device = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "ch341-uart",
+	},
+	.id_table         = id_table,
+	.usb_driver       = &ch341_driver,
+	.num_interrupt_in = NUM_DONT_CARE,
+	.num_bulk_in      = 1,
+	.num_bulk_out     = 1,
+	.num_ports        = 1,
+	.open             = ch341_open,
+	.set_termios      = ch341_set_termios,
+	.attach           = ch341_attach,
+};
+
+static int __init ch341_init(void)
+{
+	int retval;
+
+	retval = usb_serial_register(&ch341_device);
+	if (retval)
+		return retval;
+	retval = usb_register(&ch341_driver);
+	if (retval)
+		usb_serial_deregister(&ch341_device);
+	return retval;
+}
+
+static void __exit ch341_exit(void)
+{
+	usb_deregister(&ch341_driver);
+	usb_serial_deregister(&ch341_device);
+}
+
+module_init(ch341_init);
+module_exit(ch341_exit);
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+/* EOF ch341.c */
diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c
index 33f6ee5..eb7df18 100644
--- a/drivers/usb/serial/cp2101.c
+++ b/drivers/usb/serial/cp2101.c
@@ -53,6 +53,7 @@
 static int debug;
 
 static struct usb_device_id id_table [] = {
+	{ USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */
 	{ USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */
 	{ USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */
 	{ USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
@@ -521,7 +522,7 @@
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
-	if ((!port->tty) || (!port->tty->termios)) {
+	if (!port->tty || !port->tty->termios) {
 		dbg("%s - no tty structures", __FUNCTION__);
 		return;
 	}
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 2d04585..e4c248c 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -1169,7 +1169,9 @@
 	/* XXX see create_sysfs_attrs */
 	if (priv->chip_type != SIO) {
 		device_remove_file(&port->dev, &dev_attr_event_char);
-		if (priv->chip_type == FT232BM || priv->chip_type == FT2232C) {
+		if (priv->chip_type == FT232BM ||
+		    priv->chip_type == FT2232C ||
+		    priv->chip_type == FT232RL) {
 			device_remove_file(&port->dev, &dev_attr_latency_timer);
 		}
 	}
@@ -2102,6 +2104,7 @@
 	case FT8U232AM:
 	case FT232BM:
 	case FT2232C:
+	case FT232RL:
 		/* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same
 		   format as the data returned from the in point */
 		if ((ret = usb_control_msg(port->serial->dev,
diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c
index 4092f6d..b5194dc 100644
--- a/drivers/usb/serial/funsoft.c
+++ b/drivers/usb/serial/funsoft.c
@@ -24,26 +24,6 @@
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
-static int funsoft_ioctl(struct usb_serial_port *port, struct file *file,
-			 unsigned int cmd, unsigned long arg)
-{
-	struct ktermios t;
-
-	dbg("%s - port %d, cmd 0x%04x", __FUNCTION__, port->number, cmd);
-
-	if (cmd == TCSETSF) {
-		if (user_termios_to_kernel_termios(&t, (struct termios __user *)arg))
-			return -EFAULT;
-
-		dbg("%s - iflag:%x oflag:%x cflag:%x lflag:%x", __FUNCTION__,
-		    t.c_iflag, t.c_oflag, t.c_cflag, t.c_lflag);
-
-		if (!(t.c_lflag & ICANON))
-			return -EINVAL;
-	}
-	return -ENOIOCTLCMD;
-}
-
 static struct usb_driver funsoft_driver = {
 	.name =		"funsoft",
 	.probe =	usb_serial_probe,
@@ -63,7 +43,6 @@
 	.num_bulk_in =		NUM_DONT_CARE,
 	.num_bulk_out =		NUM_DONT_CARE,
 	.num_ports =		1,
-	.ioctl =		funsoft_ioctl,
 };
 
 static int __init funsoft_init(void)
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index 6a3a704..e836ad0 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -256,6 +256,7 @@
 	{ USB_DEVICE(0x04DD, 0x9121) }, /* SHARP WS004SH USB Modem */
 	{ USB_DEVICE(0x04DD, 0x9123) }, /* SHARP WS007SH USB Modem */
 	{ USB_DEVICE(0x04DD, 0x9151) }, /* SHARP S01SH USB Modem */
+	{ USB_DEVICE(0x04DD, 0x91AC) }, /* SHARP WS011SH USB Modem */
 	{ USB_DEVICE(0x04E8, 0x5F00) }, /* Samsung NEXiO USB Sync */
 	{ USB_DEVICE(0x04E8, 0x5F01) }, /* Samsung NEXiO USB Sync */
 	{ USB_DEVICE(0x04E8, 0x5F02) }, /* Samsung NEXiO USB Sync */
@@ -646,11 +647,13 @@
 	kfree(port->bulk_out_buffer);
 	port->bulk_in_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
 	if (port->bulk_in_buffer == NULL) {
+		port->bulk_out_buffer = NULL; /* prevent double free */
 		goto enomem;
 	}
 	port->bulk_out_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
 	if (port->bulk_out_buffer == NULL) {
 		kfree(port->bulk_in_buffer);
+		port->bulk_in_buffer = NULL;
 		goto enomem;
 	}
 	port->read_urb->transfer_buffer = port->bulk_in_buffer;
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index 5a4127e..90e3216 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -728,24 +728,32 @@
 #endif
 		}
 		
-		switch(cflag & CBAUD) {
-		case B0: /* handled below */
+		switch(tty_get_baud_rate(port->tty)) {
+		case 0: /* handled below */
 			break;
-		case B1200: priv->cfg.baudrate = kl5kusb105a_sio_b1200;
+		case 1200:
+			priv->cfg.baudrate = kl5kusb105a_sio_b1200;
 			break;
-		case B2400: priv->cfg.baudrate = kl5kusb105a_sio_b2400;
+		case 2400:
+			priv->cfg.baudrate = kl5kusb105a_sio_b2400;
 			break;
-		case B4800: priv->cfg.baudrate = kl5kusb105a_sio_b4800;
+		case 4800:
+			priv->cfg.baudrate = kl5kusb105a_sio_b4800;
 			break;
-		case B9600: priv->cfg.baudrate = kl5kusb105a_sio_b9600;
+		case 9600:
+			priv->cfg.baudrate = kl5kusb105a_sio_b9600;
 			break;
-		case B19200: priv->cfg.baudrate = kl5kusb105a_sio_b19200;
+		case 19200:
+			priv->cfg.baudrate = kl5kusb105a_sio_b19200;
 			break;
-		case B38400: priv->cfg.baudrate = kl5kusb105a_sio_b38400;
+		case 38400:
+			priv->cfg.baudrate = kl5kusb105a_sio_b38400;
 			break;
-		case B57600: priv->cfg.baudrate = kl5kusb105a_sio_b57600;
+		case 57600:
+			priv->cfg.baudrate = kl5kusb105a_sio_b57600;
 			break;
-		case B115200: priv->cfg.baudrate = kl5kusb105a_sio_b115200;
+		case 115200:
+			priv->cfg.baudrate = kl5kusb105a_sio_b115200;
 			break;
 		default:
 			err("KLSI USB->Serial converter:"
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index 02a86db..6f22419 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -82,6 +82,7 @@
 			   unsigned int set, unsigned int clear);
 static void kobil_read_int_callback( struct urb *urb );
 static void kobil_write_callback( struct urb *purb );
+static void kobil_set_termios(struct usb_serial_port *port, struct ktermios *old);
 
 
 static struct usb_device_id id_table [] = {
@@ -119,6 +120,7 @@
 	.attach =		kobil_startup,
 	.shutdown =		kobil_shutdown,
 	.ioctl =		kobil_ioctl,
+	.set_termios =		kobil_set_termios,
 	.tiocmget =		kobil_tiocmget,
 	.tiocmset =		kobil_tiocmset,
 	.open =			kobil_open,
@@ -137,7 +139,6 @@
 	int cur_pos; // index of the next char to send in buf
 	__u16 device_type;
 	int line_state;
-	struct ktermios internal_termios;
 };
 
 
@@ -216,7 +217,7 @@
 
 static int kobil_open (struct usb_serial_port *port, struct file *filp)
 {
-	int i, result = 0;
+	int result = 0;
 	struct kobil_private *priv;
 	unsigned char *transfer_buffer;
 	int transfer_buffer_length = 8;
@@ -242,16 +243,6 @@
 	port->tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF;
 	port->tty->termios->c_oflag &= ~ONLCR; // do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D)
 	
-	// set up internal termios structure 
-	priv->internal_termios.c_iflag = port->tty->termios->c_iflag;
-	priv->internal_termios.c_oflag = port->tty->termios->c_oflag;
-	priv->internal_termios.c_cflag = port->tty->termios->c_cflag;
-	priv->internal_termios.c_lflag = port->tty->termios->c_lflag;
-
-	for (i=0; i<NCCS; i++) {
-		priv->internal_termios.c_cc[i] = port->tty->termios->c_cc[i];
-	}
-	
 	// allocate memory for transfer buffer
 	transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL);
 	if (! transfer_buffer) {
@@ -607,102 +598,79 @@
 	return (result < 0) ? result : 0;
 }
 
-
-static int  kobil_ioctl(struct usb_serial_port *port, struct file *file,
-			unsigned int cmd, unsigned long arg)
+static void kobil_set_termios(struct usb_serial_port *port, struct ktermios *old)
 {
 	struct kobil_private * priv;
 	int result;
 	unsigned short urb_val = 0;
-	unsigned char *transfer_buffer;
-	int transfer_buffer_length = 8;
-	char *settings;
-	void __user *user_arg = (void __user *)arg;
+	int c_cflag = port->tty->termios->c_cflag;
+	speed_t speed;
+	void * settings;
 
 	priv = usb_get_serial_port_data(port);
-	if ((priv->device_type == KOBIL_USBTWIN_PRODUCT_ID) || (priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)) {
+	if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)
 		// This device doesn't support ioctl calls
-		return 0;
-	}
+		return;
 
-	switch (cmd) {
-	case TCGETS:   // 0x5401
-		if (!access_ok(VERIFY_WRITE, user_arg, sizeof(struct ktermios))) {
-			dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number);
-			return -EFAULT;
-		}
-		if (kernel_termios_to_user_termios((struct ktermios __user *)arg,
-						   &priv->internal_termios))
-			return -EFAULT;
-		return 0;
-
-	case TCSETS:   // 0x5402
-		if (!(port->tty->termios)) {
-			dbg("%s - port %d Error: port->tty->termios is NULL", __FUNCTION__, port->number);
-			return -ENOTTY;
-		}
-		if (!access_ok(VERIFY_READ, user_arg, sizeof(struct ktermios))) {
-			dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number);
-			return -EFAULT;
-		}
-		if (user_termios_to_kernel_termios(&priv->internal_termios,
-						   (struct ktermios __user *)arg))
-			return -EFAULT;
-		
-		settings = kzalloc(50, GFP_KERNEL);
-		if (! settings) {
-			return -ENOBUFS;
-		}
-
-		switch (priv->internal_termios.c_cflag & CBAUD) {
-		case B1200:
+	switch (speed = tty_get_baud_rate(port->tty)) {
+		case 1200:
 			urb_val = SUSBCR_SBR_1200;
-			strcat(settings, "1200 ");
 			break;
-		case B9600:
+		case 9600:
 		default:
 			urb_val = SUSBCR_SBR_9600;
-			strcat(settings, "9600 ");
 			break;
-		}
+	}
+	urb_val |= (c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : SUSBCR_SPASB_1StopBit;
 
-		urb_val |= (priv->internal_termios.c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : SUSBCR_SPASB_1StopBit;
-		strcat(settings, (priv->internal_termios.c_cflag & CSTOPB) ? "2 StopBits " : "1 StopBit ");
+	settings = kzalloc(50, GFP_KERNEL);
+	if (! settings)
+		return;
 
-		if (priv->internal_termios.c_cflag & PARENB) {
-			if  (priv->internal_termios.c_cflag & PARODD) {
-				urb_val |= SUSBCR_SPASB_OddParity;
-				strcat(settings, "Odd Parity");
-			} else {
-				urb_val |= SUSBCR_SPASB_EvenParity;
-				strcat(settings, "Even Parity");
-			}
+	sprintf(settings, "%d ", speed);
+
+	if (c_cflag & PARENB) {
+		if  (c_cflag & PARODD) {
+			urb_val |= SUSBCR_SPASB_OddParity;
+			strcat(settings, "Odd Parity");
 		} else {
-			urb_val |= SUSBCR_SPASB_NoParity;
-			strcat(settings, "No Parity");
+			urb_val |= SUSBCR_SPASB_EvenParity;
+			strcat(settings, "Even Parity");
 		}
-		dbg("%s - port %d setting port to: %s", __FUNCTION__, port->number, settings );
+	} else {
+		urb_val |= SUSBCR_SPASB_NoParity;
+		strcat(settings, "No Parity");
+	}
 
-		result = usb_control_msg( port->serial->dev, 
-					  usb_rcvctrlpipe(port->serial->dev, 0 ), 
-					  SUSBCRequest_SetBaudRateParityAndStopBits,
-					  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
-					  urb_val,
-					  0,
-					  settings,
-					  0,
-					  KOBIL_TIMEOUT
-			);
+	result = usb_control_msg( port->serial->dev,
+				  usb_rcvctrlpipe(port->serial->dev, 0 ),
+				  SUSBCRequest_SetBaudRateParityAndStopBits,
+				  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
+				  urb_val,
+				  0,
+				  settings,
+				  0,
+				  KOBIL_TIMEOUT
+		);
+	kfree(settings);
+}
 
-		dbg("%s - port %d Send set_baudrate URB returns: %i", __FUNCTION__, port->number, result);
-		kfree(settings);
+static int kobil_ioctl(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
+{
+	struct kobil_private * priv = usb_get_serial_port_data(port);
+	unsigned char *transfer_buffer;
+	int transfer_buffer_length = 8;
+	int result;
+
+	if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)
+		// This device doesn't support ioctl calls
 		return 0;
 
+	switch (cmd) {
 	case TCFLSH:   // 0x540B
 		transfer_buffer = kmalloc(transfer_buffer_length, GFP_KERNEL);
-		if (! transfer_buffer) {
+		if (! transfer_buffer)
 		 	return -ENOBUFS;
-		}
 
 		result = usb_control_msg( port->serial->dev, 
 		 			  usb_rcvctrlpipe(port->serial->dev, 0 ), 
@@ -716,15 +684,13 @@
 			);
 		
 		dbg("%s - port %d Send reset_all_queues (FLUSH) URB returns: %i", __FUNCTION__, port->number, result);
-
 		kfree(transfer_buffer);
-		return ((result < 0) ? -EFAULT : 0);
-
+		return (result < 0) ? -EFAULT : 0;
+	default:
+		return -ENOIOCTLCMD;
 	}
-	return -ENOIOCTLCMD;
 }
 
-
 static int __init kobil_init (void)
 {
 	int retval;
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index e08c9bb..0dc99f7 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -206,20 +206,20 @@
 		}
 	} else {
 		switch (value) {
-			case 300: break;
-			case 600: break;
-			case 1200: break;
-			case 2400: break;
-			case 4800: break;
-			case 9600: break;
-			case 19200: break;
-			case 38400: break;
-			case 57600: break;
-			case 115200: break;
-			default:
-				err("MCT USB-RS232: unsupported baudrate request 0x%x,"
-				    " using default of B9600", value);
-				value = 9600;
+		case 300: break;
+		case 600: break;
+		case 1200: break;
+		case 2400: break;
+		case 4800: break;
+		case 9600: break;
+		case 19200: break;
+		case 38400: break;
+		case 57600: break;
+		case 115200: break;
+		default:
+			err("MCT USB-RS232: unsupported baudrate request 0x%x,"
+			    " using default of B9600", value);
+			value = 9600;
 		}
 		return 115200/value;
 	}
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
index 64f3f66..d198611 100644
--- a/drivers/usb/serial/oti6858.c
+++ b/drivers/usb/serial/oti6858.c
@@ -1144,7 +1144,7 @@
 	if (size == 0)
 		return NULL;
 
-	pb = (struct pl2303_buf *)kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
+	pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
 	if (pb == NULL)
 		return NULL;
 
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index f9f85f5..1da57fd 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -73,6 +73,7 @@
 	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) },
 	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
 	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) },
+	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },
 	{ USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
 	{ USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
 	{ USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
index f9a71d0..c39bace 100644
--- a/drivers/usb/serial/pl2303.h
+++ b/drivers/usb/serial/pl2303.h
@@ -59,6 +59,7 @@
 #define SIEMENS_PRODUCT_ID_SX1	0x0001
 #define SIEMENS_PRODUCT_ID_X65	0x0003
 #define SIEMENS_PRODUCT_ID_X75	0x0004
+#define SIEMENS_PRODUCT_ID_EF81	0x0005
 
 #define SYNTECH_VENDOR_ID	0x0745
 #define SYNTECH_PRODUCT_ID	0x0001
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
index 51669b7..4e6dcc19 100644
--- a/drivers/usb/serial/safe_serial.c
+++ b/drivers/usb/serial/safe_serial.c
@@ -90,18 +90,12 @@
 MODULE_DESCRIPTION (DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
-#if defined(CONFIG_USBD_SAFE_SERIAL_VENDOR) && !defined(CONFIG_USBD_SAFE_SERIAL_PRODUCT)
-#error "SAFE_SERIAL_VENDOR defined without SAFE_SERIAL_PRODUCT"
-#endif
-
-#if ! defined(CONFIG_USBD_SAFE_SERIAL_VENDOR)
 static __u16 vendor;		// no default
 static __u16 product;		// no default
 module_param(vendor, ushort, 0);
 MODULE_PARM_DESC(vendor, "User specified USB idVendor (required)");
 module_param(product, ushort, 0);
 MODULE_PARM_DESC(product, "User specified USB idProduct (required)");
-#endif
 
 module_param(debug, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug enabled or not");
@@ -145,11 +139,6 @@
 	{MY_USB_DEVICE (0x4dd, 0x8003, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},	// Collie 
 	{MY_USB_DEVICE (0x4dd, 0x8004, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},	// Collie 
 	{MY_USB_DEVICE (0x5f9, 0xffff, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},	// Sharp tmp
-#if defined(CONFIG_USB_SAFE_SERIAL_VENDOR)
-	{MY_USB_DEVICE
-	 (CONFIG_USB_SAFE_SERIAL_VENDOR, CONFIG_USB_SAFE_SERIAL_PRODUCT, CDC_DEVICE_CLASS,
-	  LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},
-#endif
 	// extra null entry for module 
 	// vendor/produc parameters
 	{MY_USB_DEVICE (0, 0, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 9bf01a5..4b1bd7d 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -578,6 +578,17 @@
 {
 	usb_kill_urb(port->read_urb);
 	usb_kill_urb(port->write_urb);
+	/*
+	 * This is tricky.
+	 * Some drivers submit the read_urb in the
+	 * handler for the write_urb or vice versa
+	 * this order determines the order in which
+	 * usb_kill_urb() must be used to reliably
+	 * kill the URBs. As it is unknown here,
+	 * both orders must be used in turn.
+	 * The call below is not redundant.
+	 */
+	usb_kill_urb(port->read_urb);
 	usb_kill_urb(port->interrupt_in_urb);
 	usb_kill_urb(port->interrupt_out_urb);
 }
@@ -651,16 +662,14 @@
 
 static struct usb_serial_driver *search_serial_device(struct usb_interface *iface)
 {
-	struct list_head *p;
 	const struct usb_device_id *id;
-	struct usb_serial_driver *t;
+	struct usb_serial_driver *drv;
 
 	/* Check if the usb id matches a known device */
-	list_for_each(p, &usb_serial_driver_list) {
-		t = list_entry(p, struct usb_serial_driver, driver_list);
-		id = get_iface_id(t, iface);
+	list_for_each_entry(drv, &usb_serial_driver_list, driver_list) {
+		id = get_iface_id(drv, iface);
 		if (id)
-			return t;
+			return drv;
 	}
 
 	return NULL;
@@ -800,9 +809,6 @@
 	/* END HORRIBLE HACK FOR PL2303 */
 #endif
 
-	/* found all that we need */
-	dev_info(&interface->dev, "%s converter detected\n", type->description);
-
 #ifdef CONFIG_USB_SERIAL_GENERIC
 	if (type == &usb_serial_generic_device) {
 		num_ports = num_bulk_out;
@@ -836,6 +842,24 @@
 	serial->num_interrupt_in = num_interrupt_in;
 	serial->num_interrupt_out = num_interrupt_out;
 
+	/* check that the device meets the driver's requirements */
+	if ((type->num_interrupt_in != NUM_DONT_CARE &&
+				type->num_interrupt_in != num_interrupt_in)
+			|| (type->num_interrupt_out != NUM_DONT_CARE &&
+				type->num_interrupt_out != num_interrupt_out)
+			|| (type->num_bulk_in != NUM_DONT_CARE &&
+				type->num_bulk_in != num_bulk_in)
+			|| (type->num_bulk_out != NUM_DONT_CARE &&
+				type->num_bulk_out != num_bulk_out)) {
+		dbg("wrong number of endpoints");
+		kfree(serial);
+		return -EIO;
+	}
+
+	/* found all that we need */
+	dev_info(&interface->dev, "%s converter detected\n",
+			type->description);
+
 	/* create our ports, we need as many as the max endpoints */
 	/* we don't use num_ports here cauz some devices have more endpoint pairs than ports */
 	max_endpoints = max(num_bulk_in, num_bulk_out);
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 30e08c0..7ee087f 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -46,7 +46,6 @@
 static int  visor_calc_num_ports(struct usb_serial *serial);
 static void visor_shutdown	(struct usb_serial *serial);
 static int  visor_ioctl		(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
-static void visor_set_termios	(struct usb_serial_port *port, struct ktermios *old_termios);
 static void visor_write_bulk_callback	(struct urb *urb);
 static void visor_read_bulk_callback	(struct urb *urb);
 static void visor_read_int_callback	(struct urb *urb);
@@ -203,7 +202,6 @@
 	.calc_num_ports =	visor_calc_num_ports,
 	.shutdown =		visor_shutdown,
 	.ioctl =		visor_ioctl,
-	.set_termios =		visor_set_termios,
 	.write =		visor_write,
 	.write_room =		visor_write_room,
 	.chars_in_buffer =	visor_chars_in_buffer,
@@ -234,7 +232,6 @@
 	.calc_num_ports =	visor_calc_num_ports,
 	.shutdown =		visor_shutdown,
 	.ioctl =		visor_ioctl,
-	.set_termios =		visor_set_termios,
 	.write =		visor_write,
 	.write_room =		visor_write_room,
 	.chars_in_buffer =	visor_chars_in_buffer,
@@ -262,7 +259,6 @@
 	.unthrottle =		visor_unthrottle,
 	.attach =		clie_3_5_startup,
 	.ioctl =		visor_ioctl,
-	.set_termios =		visor_set_termios,
 	.write =		visor_write,
 	.write_room =		visor_write_room,
 	.chars_in_buffer =	visor_chars_in_buffer,
@@ -936,66 +932,6 @@
 	return -ENOIOCTLCMD;
 }
 
-
-/* This function is all nice and good, but we don't change anything based on it :) */
-static void visor_set_termios (struct usb_serial_port *port, struct ktermios *old_termios)
-{
-	unsigned int cflag;
-
-	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;
-
-	/* get the byte size */
-	switch (cflag & CSIZE) {
-		case CS5:	dbg("%s - data bits = 5", __FUNCTION__);   break;
-		case CS6:	dbg("%s - data bits = 6", __FUNCTION__);   break;
-		case CS7:	dbg("%s - data bits = 7", __FUNCTION__);   break;
-		default:
-		case CS8:	dbg("%s - data bits = 8", __FUNCTION__);   break;
-	}
-	
-	/* determine the parity */
-	if (cflag & PARENB)
-		if (cflag & PARODD)
-			dbg("%s - parity = odd", __FUNCTION__);
-		else
-			dbg("%s - parity = even", __FUNCTION__);
-	else
-		dbg("%s - parity = none", __FUNCTION__);
-
-	/* figure out the stop bits requested */
-	if (cflag & CSTOPB)
-		dbg("%s - stop bits = 2", __FUNCTION__);
-	else
-		dbg("%s - stop bits = 1", __FUNCTION__);
-
-	
-	/* figure out the flow control settings */
-	if (cflag & CRTSCTS)
-		dbg("%s - RTS/CTS is enabled", __FUNCTION__);
-	else
-		dbg("%s - RTS/CTS is disabled", __FUNCTION__);
-	
-	/* determine software flow control */
-	if (I_IXOFF(port->tty))
-		dbg("%s - XON/XOFF is enabled, XON = %2x, XOFF = %2x",
-		    __FUNCTION__, START_CHAR(port->tty), STOP_CHAR(port->tty));
-	else
-		dbg("%s - XON/XOFF is disabled", __FUNCTION__);
-
-	/* get the baud rate wanted */
-	dbg("%s - baud rate = %d", __FUNCTION__, tty_get_baud_rate(port->tty));
-
-	return;
-}
-
-
 static int __init visor_init (void)
 {
 	int i, retval;
diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c
index 3a41740..ee5b42a 100644
--- a/drivers/usb/storage/initializers.c
+++ b/drivers/usb/storage/initializers.c
@@ -90,3 +90,17 @@
 
 	return (res ? -1 : 0);
 }
+
+/* This places the HUAWEI E220 devices in multi-port mode */
+int usb_stor_huawei_e220_init(struct us_data *us)
+{
+	int result;
+
+	us->iobuf[0] = 0x1;
+	result = usb_stor_control_msg(us, us->send_ctrl_pipe,
+				      USB_REQ_SET_FEATURE,
+				      USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+				      0x01, 0x0, us->iobuf, 0x1, 1000);
+	US_DEBUGP("usb_control_msg performing result is %d\n", result);
+	return (result ? 0 : -1);
+}
diff --git a/drivers/usb/storage/initializers.h b/drivers/usb/storage/initializers.h
index e2967a4..ad3ffd4 100644
--- a/drivers/usb/storage/initializers.h
+++ b/drivers/usb/storage/initializers.h
@@ -47,3 +47,6 @@
 /* This function is required to activate all four slots on the UCR-61S2B
  * flash reader */
 int usb_stor_ucr61s2b_init(struct us_data *us);
+
+/* This places the HUAWEI E220 devices in multi-port mode */
+int usb_stor_huawei_e220_init(struct us_data *us);
diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c
index 5e27297..17ca4d7 100644
--- a/drivers/usb/storage/shuttle_usbat.c
+++ b/drivers/usb/storage/shuttle_usbat.c
@@ -190,9 +190,6 @@
 	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;
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index c6b78ba..9b656ec 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -198,7 +198,7 @@
 		US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
 
 /* Reported by Bardur Arantsson <bardur@scientician.net> */
-UNUSUAL_DEV(  0x0421, 0x047c, 0x0370, 0x0370,
+UNUSUAL_DEV(  0x0421, 0x047c, 0x0370, 0x0610,
 		"Nokia",
 		"6131",
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
@@ -341,6 +341,13 @@
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_FIX_CAPACITY),
 
+/* Reported by Graber and Mike Pagano <mpagano-kernel@mpagano.com> */
+UNUSUAL_DEV(  0x04b0, 0x040f, 0x0200, 0x0200,
+       "NIKON",
+       "NIKON DSC D200",
+       US_SC_DEVICE, US_PR_DEVICE, NULL,
+       US_FL_FIX_CAPACITY),
+
 /* Reported by Emil Larsson <emil@swip.net> */
 UNUSUAL_DEV(  0x04b0, 0x0411, 0x0100, 0x0101,
 		"NIKON",
@@ -355,6 +362,20 @@
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_FIX_CAPACITY),
 
+/* Reported by Paul Check <paul@openstreet.com> */
+UNUSUAL_DEV(  0x04b0, 0x0415, 0x0100, 0x0100,
+		"NIKON",
+		"NIKON DSC D2Xs",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY),
+
+/* Reported by Shan Destromp (shansan@gmail.com) */
+UNUSUAL_DEV(  0x04b0, 0x0417, 0x0100, 0x0100,
+		"NIKON",
+		"NIKON DSC D40X",
+		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> */
@@ -1463,6 +1484,17 @@
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_IGNORE_RESIDUE ),
 
+/* Reported by fangxiaozhi <fangxiaozhi60675@huawei.com>
+ * and by linlei <linlei83@huawei.com>
+ * Patch reworked by Johann Wilhelm <johann.wilhelm@student.tugraz.at>
+ * This brings the HUAWEI E220 devices into multi-port mode
+ */
+UNUSUAL_DEV( 0x12d1, 0x1003, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+
 /* Reported by Vilius Bilinkevicius <vilisas AT xxx DOT lt) */
 UNUSUAL_DEV(  0x132b, 0x000b, 0x0001, 0x0001,
 		"Minolta",
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 5918166..3451e8d0 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -960,6 +960,10 @@
 		return -ENOMEM;
 	}
 
+	/*
+	 * Allow 16-byte CDBs and thus > 2TB
+	 */
+	host->max_cmd_len = 16;
 	us = host_to_us(host);
 	memset(us, 0, sizeof(struct us_data));
 	mutex_init(&(us->dev_mutex));
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
index 8de11de..c815a40 100644
--- a/drivers/usb/usb-skeleton.c
+++ b/drivers/usb/usb-skeleton.c
@@ -125,6 +125,7 @@
 
 	/* save our object in the file's private structure */
 	file->private_data = dev;
+	mutex_unlock(&dev->io_mutex);
 
 exit:
 	return retval;
diff --git a/drivers/video/output.c b/drivers/video/output.c
index 1473f2c..f2df551 100644
--- a/drivers/video/output.c
+++ b/drivers/video/output.c
@@ -31,7 +31,8 @@
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Luming Yu <luming.yu@intel.com>");
 
-static ssize_t video_output_show_state(struct class_device *dev,char *buf)
+static ssize_t video_output_show_state(struct device *dev,
+				       struct device_attribute *attr, char *buf)
 {
 	ssize_t ret_size = 0;
 	struct output_device *od = to_output_device(dev);
@@ -40,8 +41,9 @@
 	return ret_size;
 }
 
-static ssize_t video_output_store_state(struct class_device *dev,
-	const char *buf,size_t count)
+static ssize_t video_output_store_state(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf,size_t count)
 {
 	char *endp;
 	struct output_device *od = to_output_device(dev);
@@ -60,21 +62,22 @@
 	return count;
 }
 
-static void video_output_class_release(struct class_device *dev)
+static void video_output_release(struct device *dev)
 {
 	struct output_device *od = to_output_device(dev);
 	kfree(od);
 }
 
-static struct class_device_attribute video_output_attributes[] = {
+static struct device_attribute video_output_attributes[] = {
 	__ATTR(state, 0644, video_output_show_state, video_output_store_state),
 	__ATTR_NULL,
 };
 
+
 static struct class video_output_class = {
 	.name = "video_output",
-	.release = video_output_class_release,
-	.class_dev_attrs = video_output_attributes,
+	.dev_release = video_output_release,
+	.dev_attrs = video_output_attributes,
 };
 
 struct output_device *video_output_register(const char *name,
@@ -91,11 +94,11 @@
 		goto error_return;
 	}
 	new_dev->props = op;
-	new_dev->class_dev.class = &video_output_class;
-	new_dev->class_dev.dev = dev;
-	strlcpy(new_dev->class_dev.class_id,name,KOBJ_NAME_LEN);
-	class_set_devdata(&new_dev->class_dev,devdata);
-	ret_code = class_device_register(&new_dev->class_dev);
+	new_dev->dev.class = &video_output_class;
+	new_dev->dev.parent = dev;
+	strlcpy(new_dev->dev.bus_id,name, BUS_ID_SIZE);
+	dev_set_drvdata(&new_dev->dev, devdata);
+	ret_code = device_register(&new_dev->dev);
 	if (ret_code) {
 		kfree(new_dev);
 		goto error_return;
@@ -111,7 +114,7 @@
 {
 	if (!dev)
 		return;
-	class_device_unregister(&dev->class_dev);
+	device_unregister(&dev->dev);
 }
 EXPORT_SYMBOL(video_output_unregister);
 
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index a593f90..0702173 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -197,7 +197,7 @@
 	.fops = &w1_default_fops,
 };
 
-static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size);
+static int w1_uevent(struct device *dev, struct kobj_uevent_env *env);
 
 static struct bus_type w1_bus_type = {
 	.name = "w1",
@@ -396,13 +396,12 @@
 }
 
 #ifdef CONFIG_HOTPLUG
-static int w1_uevent(struct device *dev, char **envp, int num_envp,
-			char *buffer, int buffer_size)
+static int w1_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct w1_master *md = NULL;
 	struct w1_slave *sl = NULL;
 	char *event_owner, *name;
-	int err, cur_index=0, cur_len=0;
+	int err;
 
 	if (dev->driver == &w1_master_driver) {
 		md = container_of(dev, struct w1_master, dev);
@@ -423,23 +422,19 @@
 	if (dev->driver != &w1_slave_driver || !sl)
 		return 0;
 
-	err = add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size,
-			&cur_len, "W1_FID=%02X", sl->reg_num.family);
+	err = add_uevent_var(env, "W1_FID=%02X", sl->reg_num.family);
 	if (err)
 		return err;
 
-	err = add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size,
-			&cur_len, "W1_SLAVE_ID=%024LX",
-			(unsigned long long)sl->reg_num.id);
-	envp[cur_index] = NULL;
+	err = add_uevent_var(env, "W1_SLAVE_ID=%024LX",
+			     (unsigned long long)sl->reg_num.id);
 	if (err)
 		return err;
 
 	return 0;
 };
 #else
-static int w1_uevent(struct device *dev, char **envp, int num_envp,
-			char *buffer, int buffer_size)
+static int w1_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	return 0;
 }
diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c
index 2e124e0..a9b99c0 100644
--- a/fs/debugfs/file.c
+++ b/fs/debugfs/file.c
@@ -221,6 +221,42 @@
 }
 EXPORT_SYMBOL_GPL(debugfs_create_u64);
 
+DEFINE_SIMPLE_ATTRIBUTE(fops_x8, debugfs_u8_get, debugfs_u8_set, "0x%02llx\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_x16, debugfs_u16_get, debugfs_u16_set, "0x%04llx\n");
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_x32, debugfs_u32_get, debugfs_u32_set, "0x%08llx\n");
+
+/**
+ * debugfs_create_x8 - create a debugfs file that is used to read and write an unsigned 8-bit value
+ * debugfs_create_x16 - create a debugfs file that is used to read and write an unsigned 16-bit value
+ * debugfs_create_x32 - create a debugfs file that is used to read and write an unsigned 32-bit value
+ *
+ * These functions are exactly the same as the above functions, (but use a hex
+ * output for the decimal challenged) for details look at the above unsigned
+ * decimal functions.
+ */
+struct dentry *debugfs_create_x8(const char *name, mode_t mode,
+				 struct dentry *parent, u8 *value)
+{
+	return debugfs_create_file(name, mode, parent, value, &fops_x8);
+}
+EXPORT_SYMBOL_GPL(debugfs_create_x8);
+
+struct dentry *debugfs_create_x16(const char *name, mode_t mode,
+				 struct dentry *parent, u16 *value)
+{
+	return debugfs_create_file(name, mode, parent, value, &fops_x16);
+}
+EXPORT_SYMBOL_GPL(debugfs_create_x16);
+
+struct dentry *debugfs_create_x32(const char *name, mode_t mode,
+				 struct dentry *parent, u32 *value)
+{
+	return debugfs_create_file(name, mode, parent, value, &fops_x32);
+}
+EXPORT_SYMBOL_GPL(debugfs_create_x32);
+
 static ssize_t read_file_bool(struct file *file, char __user *user_buf,
 			      size_t count, loff_t *ppos)
 {
diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h
index 74901e9..d2fc238 100644
--- a/fs/dlm/dlm_internal.h
+++ b/fs/dlm/dlm_internal.h
@@ -491,6 +491,7 @@
 	uint64_t		ls_recover_seq;
 	struct dlm_recover	*ls_recover_args;
 	struct rw_semaphore	ls_in_recovery;	/* block local requests */
+	struct rw_semaphore	ls_recv_active;	/* block dlm_recv */
 	struct list_head	ls_requestqueue;/* queue remote requests */
 	struct mutex		ls_requestqueue_mutex;
 	char			*ls_recover_buf;
diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c
index 2082daf..3915b8e1 100644
--- a/fs/dlm/lock.c
+++ b/fs/dlm/lock.c
@@ -3638,55 +3638,8 @@
 	dlm_put_lkb(lkb);
 }
 
-int dlm_receive_message(struct dlm_header *hd, int nodeid, int recovery)
+static void _receive_message(struct dlm_ls *ls, struct dlm_message *ms)
 {
-	struct dlm_message *ms = (struct dlm_message *) hd;
-	struct dlm_ls *ls;
-	int error = 0;
-
-	if (!recovery)
-		dlm_message_in(ms);
-
-	ls = dlm_find_lockspace_global(hd->h_lockspace);
-	if (!ls) {
-		log_print("drop message %d from %d for unknown lockspace %d",
-			  ms->m_type, nodeid, hd->h_lockspace);
-		return -EINVAL;
-	}
-
-	/* recovery may have just ended leaving a bunch of backed-up requests
-	   in the requestqueue; wait while dlm_recoverd clears them */
-
-	if (!recovery)
-		dlm_wait_requestqueue(ls);
-
-	/* recovery may have just started while there were a bunch of
-	   in-flight requests -- save them in requestqueue to be processed
-	   after recovery.  we can't let dlm_recvd block on the recovery
-	   lock.  if dlm_recoverd is calling this function to clear the
-	   requestqueue, it needs to be interrupted (-EINTR) if another
-	   recovery operation is starting. */
-
-	while (1) {
-		if (dlm_locking_stopped(ls)) {
-			if (recovery) {
-				error = -EINTR;
-				goto out;
-			}
-			error = dlm_add_requestqueue(ls, nodeid, hd);
-			if (error == -EAGAIN)
-				continue;
-			else {
-				error = -EINTR;
-				goto out;
-			}
-		}
-
-		if (dlm_lock_recovery_try(ls))
-			break;
-		schedule();
-	}
-
 	switch (ms->m_type) {
 
 	/* messages sent to a master node */
@@ -3761,17 +3714,90 @@
 		log_error(ls, "unknown message type %d", ms->m_type);
 	}
 
-	dlm_unlock_recovery(ls);
- out:
-	dlm_put_lockspace(ls);
 	dlm_astd_wake();
-	return error;
 }
 
+/* If the lockspace is in recovery mode (locking stopped), then normal
+   messages are saved on the requestqueue for processing after recovery is
+   done.  When not in recovery mode, we wait for dlm_recoverd to drain saved
+   messages off the requestqueue before we process new ones. This occurs right
+   after recovery completes when we transition from saving all messages on
+   requestqueue, to processing all the saved messages, to processing new
+   messages as they arrive. */
 
-/*
- * Recovery related
- */
+static void dlm_receive_message(struct dlm_ls *ls, struct dlm_message *ms,
+				int nodeid)
+{
+	if (dlm_locking_stopped(ls)) {
+		dlm_add_requestqueue(ls, nodeid, (struct dlm_header *) ms);
+	} else {
+		dlm_wait_requestqueue(ls);
+		_receive_message(ls, ms);
+	}
+}
+
+/* This is called by dlm_recoverd to process messages that were saved on
+   the requestqueue. */
+
+void dlm_receive_message_saved(struct dlm_ls *ls, struct dlm_message *ms)
+{
+	_receive_message(ls, ms);
+}
+
+/* This is called by the midcomms layer when something is received for
+   the lockspace.  It could be either a MSG (normal message sent as part of
+   standard locking activity) or an RCOM (recovery message sent as part of
+   lockspace recovery). */
+
+void dlm_receive_buffer(struct dlm_header *hd, int nodeid)
+{
+	struct dlm_message *ms = (struct dlm_message *) hd;
+	struct dlm_rcom *rc = (struct dlm_rcom *) hd;
+	struct dlm_ls *ls;
+	int type = 0;
+
+	switch (hd->h_cmd) {
+	case DLM_MSG:
+		dlm_message_in(ms);
+		type = ms->m_type;
+		break;
+	case DLM_RCOM:
+		dlm_rcom_in(rc);
+		type = rc->rc_type;
+		break;
+	default:
+		log_print("invalid h_cmd %d from %u", hd->h_cmd, nodeid);
+		return;
+	}
+
+	if (hd->h_nodeid != nodeid) {
+		log_print("invalid h_nodeid %d from %d lockspace %x",
+			  hd->h_nodeid, nodeid, hd->h_lockspace);
+		return;
+	}
+
+	ls = dlm_find_lockspace_global(hd->h_lockspace);
+	if (!ls) {
+		log_print("invalid h_lockspace %x from %d cmd %d type %d",
+			  hd->h_lockspace, nodeid, hd->h_cmd, type);
+
+		if (hd->h_cmd == DLM_RCOM && type == DLM_RCOM_STATUS)
+			dlm_send_ls_not_ready(nodeid, rc);
+		return;
+	}
+
+	/* this rwsem allows dlm_ls_stop() to wait for all dlm_recv threads to
+	   be inactive (in this ls) before transitioning to recovery mode */
+
+	down_read(&ls->ls_recv_active);
+	if (hd->h_cmd == DLM_MSG)
+		dlm_receive_message(ls, ms, nodeid);
+	else
+		dlm_receive_rcom(ls, rc, nodeid);
+	up_read(&ls->ls_recv_active);
+
+	dlm_put_lockspace(ls);
+}
 
 static void recover_convert_waiter(struct dlm_ls *ls, struct dlm_lkb *lkb)
 {
@@ -4429,7 +4455,8 @@
 
 	if (lvb_in && ua->lksb.sb_lvbptr)
 		memcpy(ua->lksb.sb_lvbptr, lvb_in, DLM_USER_LVB_LEN);
-	ua->castparam = ua_tmp->castparam;
+	if (ua_tmp->castparam)
+		ua->castparam = ua_tmp->castparam;
 	ua->user_lksb = ua_tmp->user_lksb;
 
 	error = set_unlock_args(flags, ua, &args);
@@ -4474,7 +4501,8 @@
 		goto out;
 
 	ua = (struct dlm_user_args *)lkb->lkb_astparam;
-	ua->castparam = ua_tmp->castparam;
+	if (ua_tmp->castparam)
+		ua->castparam = ua_tmp->castparam;
 	ua->user_lksb = ua_tmp->user_lksb;
 
 	error = set_unlock_args(flags, ua, &args);
diff --git a/fs/dlm/lock.h b/fs/dlm/lock.h
index 1720313..ada0468 100644
--- a/fs/dlm/lock.h
+++ b/fs/dlm/lock.h
@@ -16,7 +16,8 @@
 void dlm_print_rsb(struct dlm_rsb *r);
 void dlm_dump_rsb(struct dlm_rsb *r);
 void dlm_print_lkb(struct dlm_lkb *lkb);
-int dlm_receive_message(struct dlm_header *hd, int nodeid, int recovery);
+void dlm_receive_message_saved(struct dlm_ls *ls, struct dlm_message *ms);
+void dlm_receive_buffer(struct dlm_header *hd, int nodeid);
 int dlm_modes_compat(int mode1, int mode2);
 int dlm_find_rsb(struct dlm_ls *ls, char *name, int namelen,
 	unsigned int flags, struct dlm_rsb **r_ret);
diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c
index 1dc7210..6353a83 100644
--- a/fs/dlm/lockspace.c
+++ b/fs/dlm/lockspace.c
@@ -167,7 +167,6 @@
 };
 
 static struct kset dlm_kset = {
-	.kobj   = {.name = "dlm",},
 	.ktype  = &dlm_ktype,
 };
 
@@ -228,6 +227,7 @@
 	INIT_LIST_HEAD(&lslist);
 	spin_lock_init(&lslist_lock);
 
+	kobject_set_name(&dlm_kset.kobj, "dlm");
 	kobj_set_kset_s(&dlm_kset, kernel_subsys);
 	error = kset_register(&dlm_kset);
 	if (error)
@@ -519,6 +519,7 @@
 	ls->ls_recover_seq = 0;
 	ls->ls_recover_args = NULL;
 	init_rwsem(&ls->ls_in_recovery);
+	init_rwsem(&ls->ls_recv_active);
 	INIT_LIST_HEAD(&ls->ls_requestqueue);
 	mutex_init(&ls->ls_requestqueue_mutex);
 	mutex_init(&ls->ls_clear_proc_locks);
diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c
index 9e9d2e8..58bf3f5 100644
--- a/fs/dlm/lowcomms.c
+++ b/fs/dlm/lowcomms.c
@@ -334,18 +334,8 @@
 		con->rx_page = NULL;
 	}
 
-	/* If we are an 'othercon' then NULL the pointer to us
-	   from the parent and tidy ourself up */
-	if (test_bit(CF_IS_OTHERCON, &con->flags)) {
-		struct connection *parent = __nodeid2con(con->nodeid, 0);
-		parent->othercon = NULL;
-		kmem_cache_free(con_cache, con);
-	}
-	else {
-		/* Parent connections get reused */
-		con->retries = 0;
-		mutex_unlock(&con->sock_mutex);
-	}
+	con->retries = 0;
+	mutex_unlock(&con->sock_mutex);
 }
 
 /* We only send shutdown messages to nodes that are not part of the cluster */
@@ -731,6 +721,8 @@
 			INIT_WORK(&othercon->swork, process_send_sockets);
 			INIT_WORK(&othercon->rwork, process_recv_sockets);
 			set_bit(CF_IS_OTHERCON, &othercon->flags);
+		}
+		if (!othercon->sock) {
 			newcon->othercon = othercon;
 			othercon->sock = newsock;
 			newsock->sk->sk_user_data = othercon;
@@ -1272,14 +1264,15 @@
 		if (len) {
 			ret = sendpage(con->sock, e->page, offset, len,
 				       msg_flags);
-			if (ret == -EAGAIN || ret == 0)
+			if (ret == -EAGAIN || ret == 0) {
+				cond_resched();
 				goto out;
+			}
 			if (ret <= 0)
 				goto send_error;
-		} else {
+		}
 			/* Don't starve people filling buffers */
 			cond_resched();
-		}
 
 		spin_lock(&con->writequeue_lock);
 		e->offset += ret;
diff --git a/fs/dlm/member.c b/fs/dlm/member.c
index d099775..e9cdcab 100644
--- a/fs/dlm/member.c
+++ b/fs/dlm/member.c
@@ -18,10 +18,6 @@
 #include "rcom.h"
 #include "config.h"
 
-/*
- * Following called by dlm_recoverd thread
- */
-
 static void add_ordered_member(struct dlm_ls *ls, struct dlm_member *new)
 {
 	struct dlm_member *memb = NULL;
@@ -250,18 +246,30 @@
 	return error;
 }
 
-/*
- * Following called from lockspace.c
- */
+/* Userspace guarantees that dlm_ls_stop() has completed on all nodes before
+   dlm_ls_start() is called on any of them to start the new recovery. */
 
 int dlm_ls_stop(struct dlm_ls *ls)
 {
 	int new;
 
 	/*
-	 * A stop cancels any recovery that's in progress (see RECOVERY_STOP,
-	 * dlm_recovery_stopped()) and prevents any new locks from being
-	 * processed (see RUNNING, dlm_locking_stopped()).
+	 * Prevent dlm_recv from being in the middle of something when we do
+	 * the stop.  This includes ensuring dlm_recv isn't processing a
+	 * recovery message (rcom), while dlm_recoverd is aborting and
+	 * resetting things from an in-progress recovery.  i.e. we want
+	 * dlm_recoverd to abort its recovery without worrying about dlm_recv
+	 * processing an rcom at the same time.  Stopping dlm_recv also makes
+	 * it easy for dlm_receive_message() to check locking stopped and add a
+	 * message to the requestqueue without races.
+	 */
+
+	down_write(&ls->ls_recv_active);
+
+	/*
+	 * Abort any recovery that's in progress (see RECOVERY_STOP,
+	 * dlm_recovery_stopped()) and tell any other threads running in the
+	 * dlm to quit any processing (see RUNNING, dlm_locking_stopped()).
 	 */
 
 	spin_lock(&ls->ls_recover_lock);
@@ -271,8 +279,14 @@
 	spin_unlock(&ls->ls_recover_lock);
 
 	/*
+	 * Let dlm_recv run again, now any normal messages will be saved on the
+	 * requestqueue for later.
+	 */
+
+	up_write(&ls->ls_recv_active);
+
+	/*
 	 * This in_recovery lock does two things:
-	 *
 	 * 1) Keeps this function from returning until all threads are out
 	 *    of locking routines and locking is truely stopped.
 	 * 2) Keeps any new requests from being processed until it's unlocked
@@ -284,9 +298,8 @@
 
 	/*
 	 * The recoverd suspend/resume makes sure that dlm_recoverd (if
-	 * running) has noticed the clearing of RUNNING above and quit
-	 * processing the previous recovery.  This will be true for all nodes
-	 * before any nodes start the new recovery.
+	 * running) has noticed RECOVERY_STOP above and quit processing the
+	 * previous recovery.
 	 */
 
 	dlm_recoverd_suspend(ls);
diff --git a/fs/dlm/midcomms.c b/fs/dlm/midcomms.c
index a5126e0..f8c69dd 100644
--- a/fs/dlm/midcomms.c
+++ b/fs/dlm/midcomms.c
@@ -2,7 +2,7 @@
 *******************************************************************************
 **
 **  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
-**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2004-2007 Red Hat, Inc.  All rights reserved.
 **
 **  This copyrighted material is made available to anyone wishing to use,
 **  modify, copy, or redistribute it subject to the terms and conditions
@@ -27,7 +27,6 @@
 #include "dlm_internal.h"
 #include "lowcomms.h"
 #include "config.h"
-#include "rcom.h"
 #include "lock.h"
 #include "midcomms.h"
 
@@ -117,19 +116,7 @@
 		offset &= (limit - 1);
 		len -= msglen;
 
-		switch (msg->h_cmd) {
-		case DLM_MSG:
-			dlm_receive_message(msg, nodeid, 0);
-			break;
-
-		case DLM_RCOM:
-			dlm_receive_rcom(msg, nodeid);
-			break;
-
-		default:
-			log_print("unknown msg type %x from %u: %u %u %u %u",
-				  msg->h_cmd, nodeid, msglen, len, offset, ret);
-		}
+		dlm_receive_buffer(msg, nodeid);
 	}
 
 	if (msg != (struct dlm_header *) __tmp)
diff --git a/fs/dlm/rcom.c b/fs/dlm/rcom.c
index 188b91c..ae2fd97f 100644
--- a/fs/dlm/rcom.c
+++ b/fs/dlm/rcom.c
@@ -2,7 +2,7 @@
 *******************************************************************************
 **
 **  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
-**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2005-2007 Red Hat, Inc.  All rights reserved.
 **
 **  This copyrighted material is made available to anyone wishing to use,
 **  modify, copy, or redistribute it subject to the terms and conditions
@@ -386,7 +386,10 @@
 	dlm_recover_process_copy(ls, rc_in);
 }
 
-static int send_ls_not_ready(int nodeid, struct dlm_rcom *rc_in)
+/* If the lockspace doesn't exist then still send a status message
+   back; it's possible that it just doesn't have its global_id yet. */
+
+int dlm_send_ls_not_ready(int nodeid, struct dlm_rcom *rc_in)
 {
 	struct dlm_rcom *rc;
 	struct rcom_config *rf;
@@ -446,28 +449,11 @@
 	return rv;
 }
 
-/* Called by dlm_recvd; corresponds to dlm_receive_message() but special
+/* Called by dlm_recv; corresponds to dlm_receive_message() but special
    recovery-only comms are sent through here. */
 
-void dlm_receive_rcom(struct dlm_header *hd, int nodeid)
+void dlm_receive_rcom(struct dlm_ls *ls, struct dlm_rcom *rc, int nodeid)
 {
-	struct dlm_rcom *rc = (struct dlm_rcom *) hd;
-	struct dlm_ls *ls;
-
-	dlm_rcom_in(rc);
-
-	/* If the lockspace doesn't exist then still send a status message
-	   back; it's possible that it just doesn't have its global_id yet. */
-
-	ls = dlm_find_lockspace_global(hd->h_lockspace);
-	if (!ls) {
-		log_print("lockspace %x from %d type %x not found",
-			  hd->h_lockspace, nodeid, rc->rc_type);
-		if (rc->rc_type == DLM_RCOM_STATUS)
-			send_ls_not_ready(nodeid, rc);
-		return;
-	}
-
 	if (dlm_recovery_stopped(ls) && (rc->rc_type != DLM_RCOM_STATUS)) {
 		log_debug(ls, "ignoring recovery message %x from %d",
 			  rc->rc_type, nodeid);
@@ -477,12 +463,6 @@
 	if (is_old_reply(ls, rc))
 		goto out;
 
-	if (nodeid != rc->rc_header.h_nodeid) {
-		log_error(ls, "bad rcom nodeid %d from %d",
-			  rc->rc_header.h_nodeid, nodeid);
-		goto out;
-	}
-
 	switch (rc->rc_type) {
 	case DLM_RCOM_STATUS:
 		receive_rcom_status(ls, rc);
@@ -520,6 +500,6 @@
 		DLM_ASSERT(0, printk("rc_type=%x\n", rc->rc_type););
 	}
  out:
-	dlm_put_lockspace(ls);
+	return;
 }
 
diff --git a/fs/dlm/rcom.h b/fs/dlm/rcom.h
index d798432..b09abd2 100644
--- a/fs/dlm/rcom.h
+++ b/fs/dlm/rcom.h
@@ -2,7 +2,7 @@
 *******************************************************************************
 **
 **  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
-**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2005-2007 Red Hat, Inc.  All rights reserved.
 **
 **  This copyrighted material is made available to anyone wishing to use,
 **  modify, copy, or redistribute it subject to the terms and conditions
@@ -18,7 +18,8 @@
 int dlm_rcom_names(struct dlm_ls *ls, int nodeid, char *last_name,int last_len);
 int dlm_send_rcom_lookup(struct dlm_rsb *r, int dir_nodeid);
 int dlm_send_rcom_lock(struct dlm_rsb *r, struct dlm_lkb *lkb);
-void dlm_receive_rcom(struct dlm_header *hd, int nodeid);
+void dlm_receive_rcom(struct dlm_ls *ls, struct dlm_rcom *rc, int nodeid);
+int dlm_send_ls_not_ready(int nodeid, struct dlm_rcom *rc_in);
 
 #endif
 
diff --git a/fs/dlm/recoverd.c b/fs/dlm/recoverd.c
index 6657599..4b89e20 100644
--- a/fs/dlm/recoverd.c
+++ b/fs/dlm/recoverd.c
@@ -24,19 +24,28 @@
 
 
 /* If the start for which we're re-enabling locking (seq) has been superseded
-   by a newer stop (ls_recover_seq), we need to leave locking disabled. */
+   by a newer stop (ls_recover_seq), we need to leave locking disabled.
+
+   We suspend dlm_recv threads here to avoid the race where dlm_recv a) sees
+   locking stopped and b) adds a message to the requestqueue, but dlm_recoverd
+   enables locking and clears the requestqueue between a and b. */
 
 static int enable_locking(struct dlm_ls *ls, uint64_t seq)
 {
 	int error = -EINTR;
 
+	down_write(&ls->ls_recv_active);
+
 	spin_lock(&ls->ls_recover_lock);
 	if (ls->ls_recover_seq == seq) {
 		set_bit(LSFL_RUNNING, &ls->ls_flags);
+		/* unblocks processes waiting to enter the dlm */
 		up_write(&ls->ls_in_recovery);
 		error = 0;
 	}
 	spin_unlock(&ls->ls_recover_lock);
+
+	up_write(&ls->ls_recv_active);
 	return error;
 }
 
diff --git a/fs/dlm/requestqueue.c b/fs/dlm/requestqueue.c
index 65008d7..0de04f1 100644
--- a/fs/dlm/requestqueue.c
+++ b/fs/dlm/requestqueue.c
@@ -1,7 +1,7 @@
 /******************************************************************************
 *******************************************************************************
 **
-**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2005-2007 Red Hat, Inc.  All rights reserved.
 **
 **  This copyrighted material is made available to anyone wishing to use,
 **  modify, copy, or redistribute it subject to the terms and conditions
@@ -20,7 +20,7 @@
 struct rq_entry {
 	struct list_head list;
 	int nodeid;
-	char request[1];
+	char request[0];
 };
 
 /*
@@ -30,42 +30,39 @@
  * lockspace is enabled on some while still suspended on others.
  */
 
-int dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd)
+void dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd)
 {
 	struct rq_entry *e;
 	int length = hd->h_length;
-	int rv = 0;
 
 	e = kmalloc(sizeof(struct rq_entry) + length, GFP_KERNEL);
 	if (!e) {
-		log_print("dlm_add_requestqueue: out of memory\n");
-		return 0;
+		log_print("dlm_add_requestqueue: out of memory len %d", length);
+		return;
 	}
 
 	e->nodeid = nodeid;
 	memcpy(e->request, hd, length);
 
-	/* We need to check dlm_locking_stopped() after taking the mutex to
-	   avoid a race where dlm_recoverd enables locking and runs
-	   process_requestqueue between our earlier dlm_locking_stopped check
-	   and this addition to the requestqueue. */
-
 	mutex_lock(&ls->ls_requestqueue_mutex);
-	if (dlm_locking_stopped(ls))
-		list_add_tail(&e->list, &ls->ls_requestqueue);
-	else {
-		log_debug(ls, "dlm_add_requestqueue skip from %d", nodeid);
-		kfree(e);
-		rv = -EAGAIN;
-	}
+	list_add_tail(&e->list, &ls->ls_requestqueue);
 	mutex_unlock(&ls->ls_requestqueue_mutex);
-	return rv;
 }
 
+/*
+ * Called by dlm_recoverd to process normal messages saved while recovery was
+ * happening.  Normal locking has been enabled before this is called.  dlm_recv
+ * upon receiving a message, will wait for all saved messages to be drained
+ * here before processing the message it got.  If a new dlm_ls_stop() arrives
+ * while we're processing these saved messages, it may block trying to suspend
+ * dlm_recv if dlm_recv is waiting for us in dlm_wait_requestqueue.  In that
+ * case, we don't abort since locking_stopped is still 0.  If dlm_recv is not
+ * waiting for us, then this processing may be aborted due to locking_stopped.
+ */
+
 int dlm_process_requestqueue(struct dlm_ls *ls)
 {
 	struct rq_entry *e;
-	struct dlm_header *hd;
 	int error = 0;
 
 	mutex_lock(&ls->ls_requestqueue_mutex);
@@ -79,14 +76,7 @@
 		e = list_entry(ls->ls_requestqueue.next, struct rq_entry, list);
 		mutex_unlock(&ls->ls_requestqueue_mutex);
 
-		hd = (struct dlm_header *) e->request;
-		error = dlm_receive_message(hd, e->nodeid, 1);
-
-		if (error == -EINTR) {
-			/* entry is left on requestqueue */
-			log_debug(ls, "process_requestqueue abort eintr");
-			break;
-		}
+		dlm_receive_message_saved(ls, (struct dlm_message *)e->request);
 
 		mutex_lock(&ls->ls_requestqueue_mutex);
 		list_del(&e->list);
@@ -106,10 +96,12 @@
 
 /*
  * After recovery is done, locking is resumed and dlm_recoverd takes all the
- * saved requests and processes them as they would have been by dlm_recvd.  At
- * the same time, dlm_recvd will start receiving new requests from remote
- * nodes.  We want to delay dlm_recvd processing new requests until
- * dlm_recoverd has finished processing the old saved requests.
+ * saved requests and processes them as they would have been by dlm_recv.  At
+ * the same time, dlm_recv will start receiving new requests from remote nodes.
+ * We want to delay dlm_recv processing new requests until dlm_recoverd has
+ * finished processing the old saved requests.  We don't check for locking
+ * stopped here because dlm_ls_stop won't stop locking until it's suspended us
+ * (dlm_recv).
  */
 
 void dlm_wait_requestqueue(struct dlm_ls *ls)
@@ -118,8 +110,6 @@
 		mutex_lock(&ls->ls_requestqueue_mutex);
 		if (list_empty(&ls->ls_requestqueue))
 			break;
-		if (dlm_locking_stopped(ls))
-			break;
 		mutex_unlock(&ls->ls_requestqueue_mutex);
 		schedule();
 	}
diff --git a/fs/dlm/requestqueue.h b/fs/dlm/requestqueue.h
index 6a53ea0..aba34fc 100644
--- a/fs/dlm/requestqueue.h
+++ b/fs/dlm/requestqueue.h
@@ -1,7 +1,7 @@
 /******************************************************************************
 *******************************************************************************
 **
-**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2005-2007 Red Hat, Inc.  All rights reserved.
 **
 **  This copyrighted material is made available to anyone wishing to use,
 **  modify, copy, or redistribute it subject to the terms and conditions
@@ -13,7 +13,7 @@
 #ifndef __REQUESTQUEUE_DOT_H__
 #define __REQUESTQUEUE_DOT_H__
 
-int dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd);
+void dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd);
 int dlm_process_requestqueue(struct dlm_ls *ls);
 void dlm_wait_requestqueue(struct dlm_ls *ls);
 void dlm_purge_requestqueue(struct dlm_ls *ls);
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index cd805a6..93fa427 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -93,9 +93,10 @@
 		map_bh(bh, inode->i_sb, block);
 
 	set_buffer_uptodate(bh);
+	if (!gfs2_is_jdata(ip))
+		mark_buffer_dirty(bh);
 	if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip))
 		gfs2_trans_add_bh(ip->i_gl, bh, 0);
-	mark_buffer_dirty(bh);
 
 	if (release) {
 		unlock_page(page);
@@ -1085,6 +1086,33 @@
 	return error;
 }
 
+static int do_touch(struct gfs2_inode *ip, u64 size)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	struct buffer_head *dibh;
+	int error;
+
+	error = gfs2_trans_begin(sdp, RES_DINODE, 0);
+	if (error)
+		return error;
+
+	down_write(&ip->i_rw_mutex);
+
+	error = gfs2_meta_inode_buffer(ip, &dibh);
+	if (error)
+		goto do_touch_out;
+
+	ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;
+	gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+	gfs2_dinode_out(ip, dibh->b_data);
+	brelse(dibh);
+
+do_touch_out:
+	up_write(&ip->i_rw_mutex);
+	gfs2_trans_end(sdp);
+	return error;
+}
+
 /**
  * gfs2_truncatei - make a file a given size
  * @ip: the inode
@@ -1105,8 +1133,11 @@
 
 	if (size > ip->i_di.di_size)
 		error = do_grow(ip, size);
-	else
+	else if (size < ip->i_di.di_size)
 		error = do_shrink(ip, size);
+	else
+		/* update time stamps */
+		error = do_touch(ip, size);
 
 	return error;
 }
diff --git a/fs/gfs2/daemon.c b/fs/gfs2/daemon.c
index 3548d9f..3731ab0 100644
--- a/fs/gfs2/daemon.c
+++ b/fs/gfs2/daemon.c
@@ -35,30 +35,6 @@
    The kthread functions used to start these daemons block and flush signals. */
 
 /**
- * gfs2_scand - Look for cached glocks and inodes to toss from memory
- * @sdp: Pointer to GFS2 superblock
- *
- * One of these daemons runs, finding candidates to add to sd_reclaim_list.
- * See gfs2_glockd()
- */
-
-int gfs2_scand(void *data)
-{
-	struct gfs2_sbd *sdp = data;
-	unsigned long t;
-
-	while (!kthread_should_stop()) {
-		gfs2_scand_internal(sdp);
-		t = gfs2_tune_get(sdp, gt_scand_secs) * HZ;
-		if (freezing(current))
-			refrigerator();
-		schedule_timeout_interruptible(t);
-	}
-
-	return 0;
-}
-
-/**
  * gfs2_glockd - Reclaim unused glock structures
  * @sdp: Pointer to GFS2 superblock
  *
diff --git a/fs/gfs2/daemon.h b/fs/gfs2/daemon.h
index 80100712..0de9b35 100644
--- a/fs/gfs2/daemon.h
+++ b/fs/gfs2/daemon.h
@@ -10,7 +10,6 @@
 #ifndef __DAEMON_DOT_H__
 #define __DAEMON_DOT_H__
 
-int gfs2_scand(void *data);
 int gfs2_glockd(void *data);
 int gfs2_recoverd(void *data);
 int gfs2_logd(void *data);
diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c
index 2beb2f4..9949bb7 100644
--- a/fs/gfs2/dir.c
+++ b/fs/gfs2/dir.c
@@ -1043,6 +1043,7 @@
 
 	error = gfs2_meta_inode_buffer(dip, &dibh);
 	if (!gfs2_assert_withdraw(GFS2_SB(&dip->i_inode), !error)) {
+		gfs2_trans_add_bh(dip->i_gl, dibh, 1);
 		dip->i_di.di_blocks++;
 		gfs2_set_inode_blocks(&dip->i_inode);
 		gfs2_dinode_out(dip, dibh->b_data);
@@ -1501,7 +1502,7 @@
 		inode = gfs2_inode_lookup(dir->i_sb, 
 				be16_to_cpu(dent->de_type),
 				be64_to_cpu(dent->de_inum.no_addr),
-				be64_to_cpu(dent->de_inum.no_formal_ino));
+				be64_to_cpu(dent->de_inum.no_formal_ino), 0);
 		brelse(bh);
 		return inode;
 	}
diff --git a/fs/gfs2/eaops.c b/fs/gfs2/eaops.c
index 1ab3e9d..aa8dbf3 100644
--- a/fs/gfs2/eaops.c
+++ b/fs/gfs2/eaops.c
@@ -200,28 +200,28 @@
 	return gfs2_ea_remove_i(ip, er);
 }
 
-static struct gfs2_eattr_operations gfs2_user_eaops = {
+static const struct gfs2_eattr_operations gfs2_user_eaops = {
 	.eo_get = user_eo_get,
 	.eo_set = user_eo_set,
 	.eo_remove = user_eo_remove,
 	.eo_name = "user",
 };
 
-struct gfs2_eattr_operations gfs2_system_eaops = {
+const struct gfs2_eattr_operations gfs2_system_eaops = {
 	.eo_get = system_eo_get,
 	.eo_set = system_eo_set,
 	.eo_remove = system_eo_remove,
 	.eo_name = "system",
 };
 
-static struct gfs2_eattr_operations gfs2_security_eaops = {
+static const struct gfs2_eattr_operations gfs2_security_eaops = {
 	.eo_get = security_eo_get,
 	.eo_set = security_eo_set,
 	.eo_remove = security_eo_remove,
 	.eo_name = "security",
 };
 
-struct gfs2_eattr_operations *gfs2_ea_ops[] = {
+const struct gfs2_eattr_operations *gfs2_ea_ops[] = {
 	NULL,
 	&gfs2_user_eaops,
 	&gfs2_system_eaops,
diff --git a/fs/gfs2/eaops.h b/fs/gfs2/eaops.h
index 508b4f7..da2f7fb 100644
--- a/fs/gfs2/eaops.h
+++ b/fs/gfs2/eaops.h
@@ -22,9 +22,9 @@
 
 unsigned int gfs2_ea_name2type(const char *name, const char **truncated_name);
 
-extern struct gfs2_eattr_operations gfs2_system_eaops;
+extern const struct gfs2_eattr_operations gfs2_system_eaops;
 
-extern struct gfs2_eattr_operations *gfs2_ea_ops[];
+extern const struct gfs2_eattr_operations *gfs2_ea_ops[];
 
 #endif /* __EAOPS_DOT_H__ */
 
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 3f0974e..a37efe4 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -25,8 +25,10 @@
 #include <asm/uaccess.h>
 #include <linux/seq_file.h>
 #include <linux/debugfs.h>
-#include <linux/module.h>
-#include <linux/kallsyms.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/workqueue.h>
+#include <linux/jiffies.h>
 
 #include "gfs2.h"
 #include "incore.h"
@@ -48,7 +50,6 @@
 	int hash;                     /* hash bucket index         */
 	struct gfs2_sbd *sdp;         /* incore superblock         */
 	struct gfs2_glock *gl;        /* current glock struct      */
-	struct hlist_head *hb_list;   /* current hash bucket ptr   */
 	struct seq_file *seq;         /* sequence file for debugfs */
 	char string[512];             /* scratch space             */
 };
@@ -59,8 +60,13 @@
 static int dump_glock(struct glock_iter *gi, struct gfs2_glock *gl);
 static void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh);
 static void gfs2_glock_drop_th(struct gfs2_glock *gl);
+static void run_queue(struct gfs2_glock *gl);
+
 static DECLARE_RWSEM(gfs2_umount_flush_sem);
 static struct dentry *gfs2_root;
+static struct task_struct *scand_process;
+static unsigned int scand_secs = 5;
+static struct workqueue_struct *glock_workqueue;
 
 #define GFS2_GL_HASH_SHIFT      15
 #define GFS2_GL_HASH_SIZE       (1 << GFS2_GL_HASH_SHIFT)
@@ -276,6 +282,18 @@
 	return gl;
 }
 
+static void glock_work_func(struct work_struct *work)
+{
+	struct gfs2_glock *gl = container_of(work, struct gfs2_glock, gl_work.work);
+
+	spin_lock(&gl->gl_spin);
+	if (test_and_clear_bit(GLF_PENDING_DEMOTE, &gl->gl_flags))
+		set_bit(GLF_DEMOTE, &gl->gl_flags);
+	run_queue(gl);
+	spin_unlock(&gl->gl_spin);
+	gfs2_glock_put(gl);
+}
+
 /**
  * gfs2_glock_get() - Get a glock, or create one if one doesn't exist
  * @sdp: The GFS2 superblock
@@ -315,6 +333,7 @@
 	gl->gl_name = name;
 	atomic_set(&gl->gl_ref, 1);
 	gl->gl_state = LM_ST_UNLOCKED;
+	gl->gl_demote_state = LM_ST_EXCLUSIVE;
 	gl->gl_hash = hash;
 	gl->gl_owner_pid = 0;
 	gl->gl_ip = 0;
@@ -323,10 +342,12 @@
 	gl->gl_req_bh = NULL;
 	gl->gl_vn = 0;
 	gl->gl_stamp = jiffies;
+	gl->gl_tchange = jiffies;
 	gl->gl_object = NULL;
 	gl->gl_sbd = sdp;
 	gl->gl_aspace = NULL;
 	lops_init_le(&gl->gl_le, &gfs2_glock_lops);
+	INIT_DELAYED_WORK(&gl->gl_work, glock_work_func);
 
 	/* If this glock protects actual on-disk data or metadata blocks,
 	   create a VFS inode to manage the pages/buffers holding them. */
@@ -440,6 +461,8 @@
 
 static void gfs2_demote_wake(struct gfs2_glock *gl)
 {
+	BUG_ON(!spin_is_locked(&gl->gl_spin));
+	gl->gl_demote_state = LM_ST_EXCLUSIVE;
         clear_bit(GLF_DEMOTE, &gl->gl_flags);
         smp_mb__after_clear_bit();
         wake_up_bit(&gl->gl_flags, GLF_DEMOTE);
@@ -545,12 +568,14 @@
 		return 0;
 	}
 	set_bit(GLF_LOCK, &gl->gl_flags);
-	spin_unlock(&gl->gl_spin);
 	if (gl->gl_demote_state == LM_ST_UNLOCKED ||
-	    gl->gl_state != LM_ST_EXCLUSIVE)
+	    gl->gl_state != LM_ST_EXCLUSIVE) {
+		spin_unlock(&gl->gl_spin);
 		gfs2_glock_drop_th(gl);
-	else
+	} else {
+		spin_unlock(&gl->gl_spin);
 		gfs2_glock_xmote_th(gl, NULL);
+	}
 	spin_lock(&gl->gl_spin);
 
 	return 0;
@@ -679,24 +704,25 @@
  * practise: LM_ST_SHARED and LM_ST_UNLOCKED
  */
 
-static void handle_callback(struct gfs2_glock *gl, unsigned int state, int remote)
+static void handle_callback(struct gfs2_glock *gl, unsigned int state,
+			    int remote, unsigned long delay)
 {
+	int bit = delay ? GLF_PENDING_DEMOTE : GLF_DEMOTE;
+
 	spin_lock(&gl->gl_spin);
-	if (test_and_set_bit(GLF_DEMOTE, &gl->gl_flags) == 0) {
+	set_bit(bit, &gl->gl_flags);
+	if (gl->gl_demote_state == LM_ST_EXCLUSIVE) {
 		gl->gl_demote_state = state;
 		gl->gl_demote_time = jiffies;
 		if (remote && gl->gl_ops->go_type == LM_TYPE_IOPEN &&
 		    gl->gl_object) {
-			struct inode *inode = igrab(gl->gl_object);
+			gfs2_glock_schedule_for_reclaim(gl);
 			spin_unlock(&gl->gl_spin);
-			if (inode) {
-				d_prune_aliases(inode);
-				iput(inode);
-			}
 			return;
 		}
-	} else if (gl->gl_demote_state != LM_ST_UNLOCKED) {
-		gl->gl_demote_state = state;
+	} else if (gl->gl_demote_state != LM_ST_UNLOCKED &&
+			gl->gl_demote_state != state) {
+		gl->gl_demote_state = LM_ST_UNLOCKED;
 	}
 	spin_unlock(&gl->gl_spin);
 }
@@ -723,6 +749,7 @@
 	}
 
 	gl->gl_state = new_state;
+	gl->gl_tchange = jiffies;
 }
 
 /**
@@ -760,10 +787,20 @@
 
 	if (!gh) {
 		gl->gl_stamp = jiffies;
-		if (ret & LM_OUT_CANCELED)
+		if (ret & LM_OUT_CANCELED) {
 			op_done = 0;
-		else
+		} else {
+			spin_lock(&gl->gl_spin);
+			if (gl->gl_state != gl->gl_demote_state) {
+				gl->gl_req_bh = NULL;
+				spin_unlock(&gl->gl_spin);
+				gfs2_glock_drop_th(gl);
+				gfs2_glock_put(gl);
+				return;
+			}
 			gfs2_demote_wake(gl);
+			spin_unlock(&gl->gl_spin);
+		}
 	} else {
 		spin_lock(&gl->gl_spin);
 		list_del_init(&gh->gh_list);
@@ -799,7 +836,6 @@
 		gl->gl_req_gh = NULL;
 		gl->gl_req_bh = NULL;
 		clear_bit(GLF_LOCK, &gl->gl_flags);
-		run_queue(gl);
 		spin_unlock(&gl->gl_spin);
 	}
 
@@ -817,7 +853,7 @@
  *
  */
 
-void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh)
+static void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh)
 {
 	struct gfs2_sbd *sdp = gl->gl_sbd;
 	int flags = gh ? gh->gh_flags : 0;
@@ -871,7 +907,6 @@
 	gfs2_assert_warn(sdp, !ret);
 
 	state_change(gl, LM_ST_UNLOCKED);
-	gfs2_demote_wake(gl);
 
 	if (glops->go_inval)
 		glops->go_inval(gl, DIO_METADATA);
@@ -884,10 +919,10 @@
 	}
 
 	spin_lock(&gl->gl_spin);
+	gfs2_demote_wake(gl);
 	gl->gl_req_gh = NULL;
 	gl->gl_req_bh = NULL;
 	clear_bit(GLF_LOCK, &gl->gl_flags);
-	run_queue(gl);
 	spin_unlock(&gl->gl_spin);
 
 	gfs2_glock_put(gl);
@@ -1067,24 +1102,31 @@
 	if (test_and_set_bit(HIF_WAIT, &gh->gh_iflags))
 		BUG();
 
-	existing = find_holder_by_owner(&gl->gl_holders, gh->gh_owner_pid);
-	if (existing) {
-		print_symbol(KERN_WARNING "original: %s\n", existing->gh_ip);
-		printk(KERN_INFO "pid : %d\n", existing->gh_owner_pid);
-		printk(KERN_INFO "lock type : %d lock state : %d\n",
-				existing->gh_gl->gl_name.ln_type, existing->gh_gl->gl_state);
-		print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip);
-		printk(KERN_INFO "pid : %d\n", gh->gh_owner_pid);
-		printk(KERN_INFO "lock type : %d lock state : %d\n",
-				gl->gl_name.ln_type, gl->gl_state);
-		BUG();
-	}
-
-	existing = find_holder_by_owner(&gl->gl_waiters3, gh->gh_owner_pid);
-	if (existing) {
-		print_symbol(KERN_WARNING "original: %s\n", existing->gh_ip);
-		print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip);
-		BUG();
+	if (!(gh->gh_flags & GL_FLOCK)) {
+		existing = find_holder_by_owner(&gl->gl_holders, 
+						gh->gh_owner_pid);
+		if (existing) {
+			print_symbol(KERN_WARNING "original: %s\n", 
+				     existing->gh_ip);
+			printk(KERN_INFO "pid : %d\n", existing->gh_owner_pid);
+			printk(KERN_INFO "lock type : %d lock state : %d\n",
+			       existing->gh_gl->gl_name.ln_type, 
+			       existing->gh_gl->gl_state);
+			print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip);
+			printk(KERN_INFO "pid : %d\n", gh->gh_owner_pid);
+			printk(KERN_INFO "lock type : %d lock state : %d\n",
+			       gl->gl_name.ln_type, gl->gl_state);
+			BUG();
+		}
+		
+		existing = find_holder_by_owner(&gl->gl_waiters3, 
+						gh->gh_owner_pid);
+		if (existing) {
+			print_symbol(KERN_WARNING "original: %s\n", 
+				     existing->gh_ip);
+			print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip);
+			BUG();
+		}
 	}
 
 	if (gh->gh_flags & LM_FLAG_PRIORITY)
@@ -1195,9 +1237,10 @@
 {
 	struct gfs2_glock *gl = gh->gh_gl;
 	const struct gfs2_glock_operations *glops = gl->gl_ops;
+	unsigned delay = 0;
 
 	if (gh->gh_flags & GL_NOCACHE)
-		handle_callback(gl, LM_ST_UNLOCKED, 0);
+		handle_callback(gl, LM_ST_UNLOCKED, 0, 0);
 
 	gfs2_glmutex_lock(gl);
 
@@ -1215,8 +1258,14 @@
 	}
 
 	clear_bit(GLF_LOCK, &gl->gl_flags);
-	run_queue(gl);
 	spin_unlock(&gl->gl_spin);
+
+	gfs2_glock_hold(gl);
+	if (test_bit(GLF_PENDING_DEMOTE, &gl->gl_flags) &&
+	    !test_bit(GLF_DEMOTE, &gl->gl_flags))
+		delay = gl->gl_ops->go_min_hold_time;
+	if (queue_delayed_work(glock_workqueue, &gl->gl_work, delay) == 0)
+		gfs2_glock_put(gl);
 }
 
 void gfs2_glock_dq_wait(struct gfs2_holder *gh)
@@ -1443,18 +1492,21 @@
 			unsigned int state)
 {
 	struct gfs2_glock *gl;
+	unsigned long delay = 0;
+	unsigned long holdtime;
+	unsigned long now = jiffies;
 
 	gl = gfs2_glock_find(sdp, name);
 	if (!gl)
 		return;
 
-	handle_callback(gl, state, 1);
+	holdtime = gl->gl_tchange + gl->gl_ops->go_min_hold_time;
+	if (time_before(now, holdtime))
+		delay = holdtime - now;
 
-	spin_lock(&gl->gl_spin);
-	run_queue(gl);
-	spin_unlock(&gl->gl_spin);
-
-	gfs2_glock_put(gl);
+	handle_callback(gl, state, 1, delay);
+	if (queue_delayed_work(glock_workqueue, &gl->gl_work, delay) == 0)
+		gfs2_glock_put(gl);
 }
 
 /**
@@ -1495,7 +1547,8 @@
 			return;
 		if (!gfs2_assert_warn(sdp, gl->gl_req_bh))
 			gl->gl_req_bh(gl, async->lc_ret);
-		gfs2_glock_put(gl);
+		if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0)
+			gfs2_glock_put(gl);
 		up_read(&gfs2_umount_flush_sem);
 		return;
 	}
@@ -1588,7 +1641,7 @@
 	if (gfs2_glmutex_trylock(gl)) {
 		if (list_empty(&gl->gl_holders) &&
 		    gl->gl_state != LM_ST_UNLOCKED && demote_ok(gl))
-			handle_callback(gl, LM_ST_UNLOCKED, 0);
+			handle_callback(gl, LM_ST_UNLOCKED, 0, 0);
 		gfs2_glmutex_unlock(gl);
 	}
 
@@ -1617,7 +1670,7 @@
 		goto out;
 	gl = list_entry(head->first, struct gfs2_glock, gl_list);
 	while(1) {
-		if (gl->gl_sbd == sdp) {
+		if (!sdp || gl->gl_sbd == sdp) {
 			gfs2_glock_hold(gl);
 			read_unlock(gl_lock_addr(hash));
 			if (prev)
@@ -1635,6 +1688,7 @@
 	read_unlock(gl_lock_addr(hash));
 	if (prev)
 		gfs2_glock_put(prev);
+	cond_resched();
 	return has_entries;
 }
 
@@ -1663,20 +1717,6 @@
 }
 
 /**
- * gfs2_scand_internal - Look for glocks and inodes to toss from memory
- * @sdp: the filesystem
- *
- */
-
-void gfs2_scand_internal(struct gfs2_sbd *sdp)
-{
-	unsigned int x;
-
-	for (x = 0; x < GFS2_GL_HASH_SIZE; x++)
-		examine_bucket(scan_glock, sdp, x);
-}
-
-/**
  * clear_glock - look at a glock and see if we can free it from glock cache
  * @gl: the glock to look at
  *
@@ -1701,7 +1741,7 @@
 	if (gfs2_glmutex_trylock(gl)) {
 		if (list_empty(&gl->gl_holders) &&
 		    gl->gl_state != LM_ST_UNLOCKED)
-			handle_callback(gl, LM_ST_UNLOCKED, 0);
+			handle_callback(gl, LM_ST_UNLOCKED, 0, 0);
 		gfs2_glmutex_unlock(gl);
 	}
 }
@@ -1843,7 +1883,7 @@
 
 	spin_lock(&gl->gl_spin);
 
-	print_dbg(gi, "Glock 0x%p (%u, %llu)\n", gl, gl->gl_name.ln_type,
+	print_dbg(gi, "Glock 0x%p (%u, 0x%llx)\n", gl, gl->gl_name.ln_type,
 		   (unsigned long long)gl->gl_name.ln_number);
 	print_dbg(gi, "  gl_flags =");
 	for (x = 0; x < 32; x++) {
@@ -1963,6 +2003,35 @@
 	return error;
 }
 
+/**
+ * gfs2_scand - Look for cached glocks and inodes to toss from memory
+ * @sdp: Pointer to GFS2 superblock
+ *
+ * One of these daemons runs, finding candidates to add to sd_reclaim_list.
+ * See gfs2_glockd()
+ */
+
+static int gfs2_scand(void *data)
+{
+	unsigned x;
+	unsigned delay;
+
+	while (!kthread_should_stop()) {
+		for (x = 0; x < GFS2_GL_HASH_SIZE; x++)
+			examine_bucket(scan_glock, NULL, x);
+		if (freezing(current))
+			refrigerator();
+		delay = scand_secs;
+		if (delay < 1)
+			delay = 1;
+		schedule_timeout_interruptible(delay * HZ);
+	}
+
+	return 0;
+}
+
+
+
 int __init gfs2_glock_init(void)
 {
 	unsigned i;
@@ -1974,52 +2043,69 @@
 		rwlock_init(&gl_hash_locks[i]);
 	}
 #endif
+
+	scand_process = kthread_run(gfs2_scand, NULL, "gfs2_scand");
+	if (IS_ERR(scand_process))
+		return PTR_ERR(scand_process);
+
+	glock_workqueue = create_workqueue("glock_workqueue");
+	if (IS_ERR(glock_workqueue)) {
+		kthread_stop(scand_process);
+		return PTR_ERR(glock_workqueue);
+	}
+
 	return 0;
 }
 
+void gfs2_glock_exit(void)
+{
+	destroy_workqueue(glock_workqueue);
+	kthread_stop(scand_process);
+}
+
+module_param(scand_secs, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(scand_secs, "The number of seconds between scand runs");
+
 static int gfs2_glock_iter_next(struct glock_iter *gi)
 {
+	struct gfs2_glock *gl;
+
+restart:
 	read_lock(gl_lock_addr(gi->hash));
-	while (1) {
-		if (!gi->hb_list) {  /* If we don't have a hash bucket yet */
-			gi->hb_list = &gl_hash_table[gi->hash].hb_list;
-			if (hlist_empty(gi->hb_list)) {
-				read_unlock(gl_lock_addr(gi->hash));
-				gi->hash++;
-				read_lock(gl_lock_addr(gi->hash));
-				gi->hb_list = NULL;
-				if (gi->hash >= GFS2_GL_HASH_SIZE) {
-					read_unlock(gl_lock_addr(gi->hash));
-					return 1;
-				}
-				else
-					continue;
-			}
-			if (!hlist_empty(gi->hb_list)) {
-				gi->gl = list_entry(gi->hb_list->first,
-						    struct gfs2_glock,
-						    gl_list);
-			}
-		} else {
-			if (gi->gl->gl_list.next == NULL) {
-				read_unlock(gl_lock_addr(gi->hash));
-				gi->hash++;
-				read_lock(gl_lock_addr(gi->hash));
-				gi->hb_list = NULL;
-				continue;
-			}
-			gi->gl = list_entry(gi->gl->gl_list.next,
-					    struct gfs2_glock, gl_list);
-		}
+	gl = gi->gl;
+	if (gl) {
+		gi->gl = hlist_entry(gl->gl_list.next,
+				     struct gfs2_glock, gl_list);
 		if (gi->gl)
-			break;
+			gfs2_glock_hold(gi->gl);
 	}
 	read_unlock(gl_lock_addr(gi->hash));
+	if (gl)
+		gfs2_glock_put(gl);
+	if (gl && gi->gl == NULL)
+		gi->hash++;
+	while(gi->gl == NULL) {
+		if (gi->hash >= GFS2_GL_HASH_SIZE)
+			return 1;
+		read_lock(gl_lock_addr(gi->hash));
+		gi->gl = hlist_entry(gl_hash_table[gi->hash].hb_list.first,
+				     struct gfs2_glock, gl_list);
+		if (gi->gl)
+			gfs2_glock_hold(gi->gl);
+		read_unlock(gl_lock_addr(gi->hash));
+		gi->hash++;
+	}
+
+	if (gi->sdp != gi->gl->gl_sbd)
+		goto restart;
+
 	return 0;
 }
 
 static void gfs2_glock_iter_free(struct glock_iter *gi)
 {
+	if (gi->gl)
+		gfs2_glock_put(gi->gl);
 	kfree(gi);
 }
 
@@ -2033,9 +2119,8 @@
 
 	gi->sdp = sdp;
 	gi->hash = 0;
-	gi->gl = NULL;
-	gi->hb_list = NULL;
 	gi->seq = NULL;
+	gi->gl = NULL;
 	memset(gi->string, 0, sizeof(gi->string));
 
 	if (gfs2_glock_iter_next(gi)) {
@@ -2055,7 +2140,7 @@
 	if (!gi)
 		return NULL;
 
-	while (n--) {
+	while(n--) {
 		if (gfs2_glock_iter_next(gi)) {
 			gfs2_glock_iter_free(gi);
 			return NULL;
@@ -2082,7 +2167,9 @@
 
 static void gfs2_glock_seq_stop(struct seq_file *file, void *iter_ptr)
 {
-	/* nothing for now */
+	struct glock_iter *gi = iter_ptr;
+	if (gi)
+		gfs2_glock_iter_free(gi);
 }
 
 static int gfs2_glock_seq_show(struct seq_file *file, void *iter_ptr)
@@ -2095,7 +2182,7 @@
 	return 0;
 }
 
-static struct seq_operations gfs2_glock_seq_ops = {
+static const struct seq_operations gfs2_glock_seq_ops = {
 	.start = gfs2_glock_seq_start,
 	.next  = gfs2_glock_seq_next,
 	.stop  = gfs2_glock_seq_stop,
diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h
index 7721ca3..b16f604 100644
--- a/fs/gfs2/glock.h
+++ b/fs/gfs2/glock.h
@@ -26,6 +26,7 @@
 #define GL_SKIP			0x00000100
 #define GL_ATIME		0x00000200
 #define GL_NOCACHE		0x00000400
+#define GL_FLOCK		0x00000800
 #define GL_NOCANCEL		0x00001000
 
 #define GLR_TRYFAILED		13
@@ -132,11 +133,11 @@
 
 void gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl);
 void gfs2_reclaim_glock(struct gfs2_sbd *sdp);
-
-void gfs2_scand_internal(struct gfs2_sbd *sdp);
 void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait);
 
 int __init gfs2_glock_init(void);
+void gfs2_glock_exit(void);
+
 int gfs2_create_debugfs_file(struct gfs2_sbd *sdp);
 void gfs2_delete_debugfs_file(struct gfs2_sbd *sdp);
 int gfs2_register_debugfs(void);
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
index 777ca46..4670dcb 100644
--- a/fs/gfs2/glops.c
+++ b/fs/gfs2/glops.c
@@ -41,7 +41,6 @@
 	struct list_head *head = &gl->gl_ail_list;
 	struct gfs2_bufdata *bd;
 	struct buffer_head *bh;
-	u64 blkno;
 	int error;
 
 	blocks = atomic_read(&gl->gl_ail_count);
@@ -57,19 +56,12 @@
 		bd = list_entry(head->next, struct gfs2_bufdata,
 				bd_ail_gl_list);
 		bh = bd->bd_bh;
-		blkno = bh->b_blocknr;
+		gfs2_remove_from_ail(NULL, bd);
+		bd->bd_bh = NULL;
+		bh->b_private = NULL;
+		bd->bd_blkno = bh->b_blocknr;
 		gfs2_assert_withdraw(sdp, !buffer_busy(bh));
-
-		bd->bd_ail = NULL;
-		list_del(&bd->bd_ail_st_list);
-		list_del(&bd->bd_ail_gl_list);
-		atomic_dec(&gl->gl_ail_count);
-		brelse(bh);
-		gfs2_log_unlock(sdp);
-
-		gfs2_trans_add_revoke(sdp, blkno);
-
-		gfs2_log_lock(sdp);
+		gfs2_trans_add_revoke(sdp, bd);
 	}
 	gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count));
 	gfs2_log_unlock(sdp);
@@ -156,9 +148,11 @@
 		ip = NULL;
 
 	if (test_bit(GLF_DIRTY, &gl->gl_flags)) {
-		if (ip)
+		if (ip && !gfs2_is_jdata(ip))
 			filemap_fdatawrite(ip->i_inode.i_mapping);
 		gfs2_log_flush(gl->gl_sbd, gl);
+		if (ip && gfs2_is_jdata(ip))
+			filemap_fdatawrite(ip->i_inode.i_mapping);
 		gfs2_meta_sync(gl);
 		if (ip) {
 			struct address_space *mapping = ip->i_inode.i_mapping;
@@ -452,6 +446,7 @@
 	.go_lock = inode_go_lock,
 	.go_unlock = inode_go_unlock,
 	.go_type = LM_TYPE_INODE,
+	.go_min_hold_time = HZ / 10,
 };
 
 const struct gfs2_glock_operations gfs2_rgrp_glops = {
@@ -462,6 +457,7 @@
 	.go_lock = rgrp_go_lock,
 	.go_unlock = rgrp_go_unlock,
 	.go_type = LM_TYPE_RGRP,
+	.go_min_hold_time = HZ / 10,
 };
 
 const struct gfs2_glock_operations gfs2_trans_glops = {
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index 170ba93..eaddfb5 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -11,6 +11,7 @@
 #define __INCORE_DOT_H__
 
 #include <linux/fs.h>
+#include <linux/workqueue.h>
 
 #define DIO_WAIT	0x00000010
 #define DIO_METADATA	0x00000020
@@ -113,7 +114,13 @@
 	struct buffer_head *bd_bh;
 	struct gfs2_glock *bd_gl;
 
-	struct list_head bd_list_tr;
+	union {
+		struct list_head list_tr;
+		u64 blkno;
+	} u;
+#define bd_list_tr u.list_tr
+#define bd_blkno u.blkno
+
 	struct gfs2_log_element bd_le;
 
 	struct gfs2_ail *bd_ail;
@@ -130,6 +137,7 @@
 	int (*go_lock) (struct gfs2_holder *gh);
 	void (*go_unlock) (struct gfs2_holder *gh);
 	const int go_type;
+	const unsigned long go_min_hold_time;
 };
 
 enum {
@@ -161,6 +169,7 @@
 	GLF_LOCK		= 1,
 	GLF_STICKY		= 2,
 	GLF_DEMOTE		= 3,
+	GLF_PENDING_DEMOTE	= 4,
 	GLF_DIRTY		= 5,
 };
 
@@ -193,6 +202,7 @@
 
 	u64 gl_vn;
 	unsigned long gl_stamp;
+	unsigned long gl_tchange;
 	void *gl_object;
 
 	struct list_head gl_reclaim;
@@ -203,6 +213,7 @@
 	struct gfs2_log_element gl_le;
 	struct list_head gl_ail_list;
 	atomic_t gl_ail_count;
+	struct delayed_work gl_work;
 };
 
 struct gfs2_alloc {
@@ -293,11 +304,6 @@
 	struct gfs2_holder f_fl_gh;
 };
 
-struct gfs2_revoke {
-	struct gfs2_log_element rv_le;
-	u64 rv_blkno;
-};
-
 struct gfs2_revoke_replay {
 	struct list_head rr_list;
 	u64 rr_blkno;
@@ -335,12 +341,6 @@
 	unsigned long qd_last_touched;
 };
 
-struct gfs2_log_buf {
-	struct list_head lb_list;
-	struct buffer_head *lb_bh;
-	struct buffer_head *lb_real;
-};
-
 struct gfs2_trans {
 	unsigned long tr_ip;
 
@@ -429,7 +429,6 @@
 	unsigned int gt_log_flush_secs;
 	unsigned int gt_jindex_refresh_secs; /* Check for new journal index */
 
-	unsigned int gt_scand_secs;
 	unsigned int gt_recoverd_secs;
 	unsigned int gt_logd_secs;
 	unsigned int gt_quotad_secs;
@@ -574,7 +573,6 @@
 
 	/* Daemon stuff */
 
-	struct task_struct *sd_scand_process;
 	struct task_struct *sd_recoverd_process;
 	struct task_struct *sd_logd_process;
 	struct task_struct *sd_quotad_process;
@@ -609,13 +607,13 @@
 	unsigned int sd_log_num_revoke;
 	unsigned int sd_log_num_rg;
 	unsigned int sd_log_num_databuf;
-	unsigned int sd_log_num_jdata;
 
 	struct list_head sd_log_le_gl;
 	struct list_head sd_log_le_buf;
 	struct list_head sd_log_le_revoke;
 	struct list_head sd_log_le_rg;
 	struct list_head sd_log_le_databuf;
+	struct list_head sd_log_le_ordered;
 
 	unsigned int sd_log_blks_free;
 	struct mutex sd_log_reserve_mutex;
@@ -627,7 +625,8 @@
 
 	unsigned long sd_log_flush_time;
 	struct rw_semaphore sd_log_flush_lock;
-	struct list_head sd_log_flush_list;
+	atomic_t sd_log_in_flight;
+	wait_queue_head_t sd_log_flush_wait;
 
 	unsigned int sd_log_flush_head;
 	u64 sd_log_flush_wrapped;
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 34f7bcd..5f6dc32 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -77,6 +77,49 @@
 	return iget5_locked(sb, hash, iget_test, iget_set, &no_addr);
 }
 
+struct gfs2_skip_data {
+	u64	no_addr;
+	int	skipped;
+};
+
+static int iget_skip_test(struct inode *inode, void *opaque)
+{
+	struct gfs2_inode *ip = GFS2_I(inode);
+	struct gfs2_skip_data *data = opaque;
+
+	if (ip->i_no_addr == data->no_addr && inode->i_private != NULL){
+		if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE)){
+			data->skipped = 1;
+			return 0;
+		}
+		return 1;
+	}
+	return 0;
+}
+
+static int iget_skip_set(struct inode *inode, void *opaque)
+{
+	struct gfs2_inode *ip = GFS2_I(inode);
+	struct gfs2_skip_data *data = opaque;
+
+	if (data->skipped)
+		return 1;
+	inode->i_ino = (unsigned long)(data->no_addr);
+	ip->i_no_addr = data->no_addr;
+	return 0;
+}
+
+static struct inode *gfs2_iget_skip(struct super_block *sb,
+				    u64 no_addr)
+{
+	struct gfs2_skip_data data;
+	unsigned long hash = (unsigned long)no_addr;
+
+	data.no_addr = no_addr;
+	data.skipped = 0;
+	return iget5_locked(sb, hash, iget_skip_test, iget_skip_set, &data);
+}
+
 /**
  * GFS2 lookup code fills in vfs inode contents based on info obtained
  * from directory entry inside gfs2_inode_lookup(). This has caused issues
@@ -112,6 +155,7 @@
  * @sb: The super block
  * @no_addr: The inode number
  * @type: The type of the inode
+ * @skip_freeing: set this not return an inode if it is currently being freed.
  *
  * Returns: A VFS inode, or an error
  */
@@ -119,13 +163,19 @@
 struct inode *gfs2_inode_lookup(struct super_block *sb, 
 				unsigned int type,
 				u64 no_addr,
-				u64 no_formal_ino)
+				u64 no_formal_ino, int skip_freeing)
 {
-	struct inode *inode = gfs2_iget(sb, no_addr);
-	struct gfs2_inode *ip = GFS2_I(inode);
+	struct inode *inode;
+	struct gfs2_inode *ip;
 	struct gfs2_glock *io_gl;
 	int error;
 
+	if (skip_freeing)
+		inode = gfs2_iget_skip(sb, no_addr);
+	else
+		inode = gfs2_iget(sb, no_addr);
+	ip = GFS2_I(inode);
+
 	if (!inode)
 		return ERR_PTR(-ENOBUFS);
 
@@ -244,6 +294,11 @@
 	return 0;
 }
 
+static void gfs2_inode_bh(struct gfs2_inode *ip, struct buffer_head *bh)
+{
+	ip->i_cache[0] = bh;
+}
+
 /**
  * gfs2_inode_refresh - Refresh the incore copy of the dinode
  * @ip: The GFS2 inode
@@ -688,7 +743,7 @@
 static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl,
 			const struct gfs2_inum_host *inum, unsigned int mode,
 			unsigned int uid, unsigned int gid,
-			const u64 *generation, dev_t dev)
+			const u64 *generation, dev_t dev, struct buffer_head **bhp)
 {
 	struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
 	struct gfs2_dinode *di;
@@ -743,13 +798,15 @@
 	di->di_mtime_nsec = cpu_to_be32(tv.tv_nsec);
 	di->di_ctime_nsec = cpu_to_be32(tv.tv_nsec);
 	memset(&di->di_reserved, 0, sizeof(di->di_reserved));
+	
+	set_buffer_uptodate(dibh);
 
-	brelse(dibh);
+	*bhp = dibh;
 }
 
 static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl,
 		       unsigned int mode, const struct gfs2_inum_host *inum,
-		       const u64 *generation, dev_t dev)
+		       const u64 *generation, dev_t dev, struct buffer_head **bhp)
 {
 	struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
 	unsigned int uid, gid;
@@ -770,7 +827,7 @@
 	if (error)
 		goto out_quota;
 
-	init_dinode(dip, gl, inum, mode, uid, gid, generation, dev);
+	init_dinode(dip, gl, inum, mode, uid, gid, generation, dev, bhp);
 	gfs2_quota_change(dip, +1, uid, gid);
 	gfs2_trans_end(sdp);
 
@@ -909,6 +966,7 @@
 	struct gfs2_inum_host inum = { .no_addr = 0, .no_formal_ino = 0 };
 	int error;
 	u64 generation;
+	struct buffer_head *bh=NULL;
 
 	if (!name->len || name->len > GFS2_FNAMESIZE)
 		return ERR_PTR(-ENAMETOOLONG);
@@ -935,16 +993,18 @@
 	if (error)
 		goto fail_gunlock;
 
-	error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation, dev);
+	error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation, dev, &bh);
 	if (error)
 		goto fail_gunlock2;
 
 	inode = gfs2_inode_lookup(dir->i_sb, IF2DT(mode),
 					inum.no_addr,
-					inum.no_formal_ino);
+					inum.no_formal_ino, 0);
 	if (IS_ERR(inode))
 		goto fail_gunlock2;
 
+	gfs2_inode_bh(GFS2_I(inode), bh);
+
 	error = gfs2_inode_refresh(GFS2_I(inode));
 	if (error)
 		goto fail_gunlock2;
diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h
index 4517ac8..351ac87 100644
--- a/fs/gfs2/inode.h
+++ b/fs/gfs2/inode.h
@@ -49,7 +49,8 @@
 void gfs2_inode_attr_in(struct gfs2_inode *ip);
 void gfs2_set_iop(struct inode *inode);
 struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type, 
-				u64 no_addr, u64 no_formal_ino);
+				u64 no_addr, u64 no_formal_ino,
+				int skip_freeing);
 struct inode *gfs2_ilookup(struct super_block *sb, u64 no_addr);
 
 int gfs2_inode_refresh(struct gfs2_inode *ip);
diff --git a/fs/gfs2/locking/dlm/lock_dlm.h b/fs/gfs2/locking/dlm/lock_dlm.h
index 24d70f7..9e8265d 100644
--- a/fs/gfs2/locking/dlm/lock_dlm.h
+++ b/fs/gfs2/locking/dlm/lock_dlm.h
@@ -13,7 +13,6 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
-#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/list.h>
diff --git a/fs/gfs2/locking/dlm/plock.c b/fs/gfs2/locking/dlm/plock.c
index fba1f1d..1f7b038 100644
--- a/fs/gfs2/locking/dlm/plock.c
+++ b/fs/gfs2/locking/dlm/plock.c
@@ -346,15 +346,16 @@
 
 static unsigned int dev_poll(struct file *file, poll_table *wait)
 {
+	unsigned int mask = 0;
+
 	poll_wait(file, &send_wq, wait);
 
 	spin_lock(&ops_lock);
-	if (!list_empty(&send_list)) {
-		spin_unlock(&ops_lock);
-		return POLLIN | POLLRDNORM;
-	}
+	if (!list_empty(&send_list))
+		mask = POLLIN | POLLRDNORM;
 	spin_unlock(&ops_lock);
-	return 0;
+
+	return mask;
 }
 
 static const struct file_operations dev_fops = {
diff --git a/fs/gfs2/locking/dlm/sysfs.c b/fs/gfs2/locking/dlm/sysfs.c
index d9fe3ca..ae9e6a2 100644
--- a/fs/gfs2/locking/dlm/sysfs.c
+++ b/fs/gfs2/locking/dlm/sysfs.c
@@ -190,7 +190,6 @@
 };
 
 static struct kset gdlm_kset = {
-	.kobj   = {.name = "lock_dlm",},
 	.ktype  = &gdlm_ktype,
 };
 
@@ -224,6 +223,7 @@
 {
 	int error;
 
+	kobject_set_name(&gdlm_kset.kobj, "lock_dlm");
 	kobj_set_kset_s(&gdlm_kset, kernel_subsys);
 	error = kset_register(&gdlm_kset);
 	if (error)
diff --git a/fs/gfs2/locking/dlm/thread.c b/fs/gfs2/locking/dlm/thread.c
index 1aca51e..bd938f0 100644
--- a/fs/gfs2/locking/dlm/thread.c
+++ b/fs/gfs2/locking/dlm/thread.c
@@ -268,20 +268,16 @@
 	return 0;
 }
 
-static int gdlm_thread(void *data)
+static int gdlm_thread(void *data, int blist)
 {
 	struct gdlm_ls *ls = (struct gdlm_ls *) data;
 	struct gdlm_lock *lp = NULL;
-	int blist = 0;
 	uint8_t complete, blocking, submit, drop;
 	DECLARE_WAITQUEUE(wait, current);
 
 	/* Only thread1 is allowed to do blocking callbacks since gfs
 	   may wait for a completion callback within a blocking cb. */
 
-	if (current == ls->thread1)
-		blist = 1;
-
 	while (!kthread_should_stop()) {
 		set_current_state(TASK_INTERRUPTIBLE);
 		add_wait_queue(&ls->thread_wait, &wait);
@@ -333,12 +329,22 @@
 	return 0;
 }
 
+static int gdlm_thread1(void *data)
+{
+	return gdlm_thread(data, 1);
+}
+
+static int gdlm_thread2(void *data)
+{
+	return gdlm_thread(data, 0);
+}
+
 int gdlm_init_threads(struct gdlm_ls *ls)
 {
 	struct task_struct *p;
 	int error;
 
-	p = kthread_run(gdlm_thread, ls, "lock_dlm1");
+	p = kthread_run(gdlm_thread1, ls, "lock_dlm1");
 	error = IS_ERR(p);
 	if (error) {
 		log_error("can't start lock_dlm1 thread %d", error);
@@ -346,7 +352,7 @@
 	}
 	ls->thread1 = p;
 
-	p = kthread_run(gdlm_thread, ls, "lock_dlm2");
+	p = kthread_run(gdlm_thread2, ls, "lock_dlm2");
 	error = IS_ERR(p);
 	if (error) {
 		log_error("can't start lock_dlm2 thread %d", error);
diff --git a/fs/gfs2/locking/nolock/main.c b/fs/gfs2/locking/nolock/main.c
index 0d149c8c..d3b8ce6 100644
--- a/fs/gfs2/locking/nolock/main.c
+++ b/fs/gfs2/locking/nolock/main.c
@@ -9,7 +9,6 @@
 
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/fs.h>
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c
index f49a12e..7df7024 100644
--- a/fs/gfs2/log.c
+++ b/fs/gfs2/log.c
@@ -60,6 +60,26 @@
 }
 
 /**
+ * gfs2_remove_from_ail - Remove an entry from the ail lists, updating counters
+ * @mapping: The associated mapping (maybe NULL)
+ * @bd: The gfs2_bufdata to remove
+ *
+ * The log lock _must_ be held when calling this function
+ *
+ */
+
+void gfs2_remove_from_ail(struct address_space *mapping, struct gfs2_bufdata *bd)
+{
+	bd->bd_ail = NULL;
+	list_del_init(&bd->bd_ail_st_list);
+	list_del_init(&bd->bd_ail_gl_list);
+	atomic_dec(&bd->bd_gl->gl_ail_count);
+	if (mapping)
+		gfs2_meta_cache_flush(GFS2_I(mapping->host));
+	brelse(bd->bd_bh);
+}
+
+/**
  * gfs2_ail1_start_one - Start I/O on a part of the AIL
  * @sdp: the filesystem
  * @tr: the part of the AIL
@@ -83,17 +103,9 @@
 
 			gfs2_assert(sdp, bd->bd_ail == ai);
 
-			if (!bh){
-				list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list);
-                                continue;
-                        }
-
 			if (!buffer_busy(bh)) {
-				if (!buffer_uptodate(bh)) {
-					gfs2_log_unlock(sdp);
+				if (!buffer_uptodate(bh))
 					gfs2_io_error_bh(sdp, bh);
-					gfs2_log_lock(sdp);
-				}
 				list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list);
 				continue;
 			}
@@ -103,9 +115,16 @@
 
 			list_move(&bd->bd_ail_st_list, &ai->ai_ail1_list);
 
+			get_bh(bh);
 			gfs2_log_unlock(sdp);
-			wait_on_buffer(bh);
-			ll_rw_block(WRITE, 1, &bh);
+			lock_buffer(bh);
+			if (test_clear_buffer_dirty(bh)) {
+				bh->b_end_io = end_buffer_write_sync;
+				submit_bh(WRITE, bh);
+			} else {
+				unlock_buffer(bh);
+				brelse(bh);
+			}
 			gfs2_log_lock(sdp);
 
 			retry = 1;
@@ -130,11 +149,6 @@
 					 bd_ail_st_list) {
 		bh = bd->bd_bh;
 
-		if (!bh){
-			list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list);
-			continue;
-		}
-
 		gfs2_assert(sdp, bd->bd_ail == ai);
 
 		if (buffer_busy(bh)) {
@@ -155,13 +169,14 @@
 
 static void gfs2_ail1_start(struct gfs2_sbd *sdp, int flags)
 {
-	struct list_head *head = &sdp->sd_ail1_list;
+	struct list_head *head;
 	u64 sync_gen;
 	struct list_head *first;
 	struct gfs2_ail *first_ai, *ai, *tmp;
 	int done = 0;
 
 	gfs2_log_lock(sdp);
+	head = &sdp->sd_ail1_list;
 	if (list_empty(head)) {
 		gfs2_log_unlock(sdp);
 		return;
@@ -233,11 +248,7 @@
 		bd = list_entry(head->prev, struct gfs2_bufdata,
 				bd_ail_st_list);
 		gfs2_assert(sdp, bd->bd_ail == ai);
-		bd->bd_ail = NULL;
-		list_del(&bd->bd_ail_st_list);
-		list_del(&bd->bd_ail_gl_list);
-		atomic_dec(&bd->bd_gl->gl_ail_count);
-		brelse(bd->bd_bh);
+		gfs2_remove_from_ail(bd->bd_bh->b_page->mapping, bd);
 	}
 }
 
@@ -439,10 +450,10 @@
 	return tail;
 }
 
-static inline void log_incr_head(struct gfs2_sbd *sdp)
+void gfs2_log_incr_head(struct gfs2_sbd *sdp)
 {
 	if (sdp->sd_log_flush_head == sdp->sd_log_tail)
-		gfs2_assert_withdraw(sdp, sdp->sd_log_flush_head == sdp->sd_log_head);
+		BUG_ON(sdp->sd_log_flush_head != sdp->sd_log_head);
 
 	if (++sdp->sd_log_flush_head == sdp->sd_jdesc->jd_blocks) {
 		sdp->sd_log_flush_head = 0;
@@ -451,6 +462,23 @@
 }
 
 /**
+ * gfs2_log_write_endio - End of I/O for a log buffer
+ * @bh: The buffer head
+ * @uptodate: I/O Status
+ *
+ */
+
+static void gfs2_log_write_endio(struct buffer_head *bh, int uptodate)
+{
+	struct gfs2_sbd *sdp = bh->b_private;
+	bh->b_private = NULL;
+
+	end_buffer_write_sync(bh, uptodate);
+	if (atomic_dec_and_test(&sdp->sd_log_in_flight))
+		wake_up(&sdp->sd_log_flush_wait);
+}
+
+/**
  * gfs2_log_get_buf - Get and initialize a buffer to use for log control data
  * @sdp: The GFS2 superblock
  *
@@ -460,25 +488,43 @@
 struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp)
 {
 	u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head);
-	struct gfs2_log_buf *lb;
 	struct buffer_head *bh;
 
-	lb = kzalloc(sizeof(struct gfs2_log_buf), GFP_NOFS | __GFP_NOFAIL);
-	list_add(&lb->lb_list, &sdp->sd_log_flush_list);
-
-	bh = lb->lb_bh = sb_getblk(sdp->sd_vfs, blkno);
+	bh = sb_getblk(sdp->sd_vfs, blkno);
 	lock_buffer(bh);
 	memset(bh->b_data, 0, bh->b_size);
 	set_buffer_uptodate(bh);
 	clear_buffer_dirty(bh);
-	unlock_buffer(bh);
-
-	log_incr_head(sdp);
+	gfs2_log_incr_head(sdp);
+	atomic_inc(&sdp->sd_log_in_flight);
+	bh->b_private = sdp;
+	bh->b_end_io = gfs2_log_write_endio;
 
 	return bh;
 }
 
 /**
+ * gfs2_fake_write_endio - 
+ * @bh: The buffer head
+ * @uptodate: The I/O Status
+ *
+ */
+
+static void gfs2_fake_write_endio(struct buffer_head *bh, int uptodate)
+{
+	struct buffer_head *real_bh = bh->b_private;
+	struct gfs2_bufdata *bd = real_bh->b_private;
+	struct gfs2_sbd *sdp = bd->bd_gl->gl_sbd;
+
+	end_buffer_write_sync(bh, uptodate);
+	free_buffer_head(bh);
+	unlock_buffer(real_bh);
+	brelse(real_bh);
+	if (atomic_dec_and_test(&sdp->sd_log_in_flight))
+		wake_up(&sdp->sd_log_flush_wait);
+}
+
+/**
  * gfs2_log_fake_buf - Build a fake buffer head to write metadata buffer to log
  * @sdp: the filesystem
  * @data: the data the buffer_head should point to
@@ -490,22 +536,20 @@
 				      struct buffer_head *real)
 {
 	u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head);
-	struct gfs2_log_buf *lb;
 	struct buffer_head *bh;
 
-	lb = kzalloc(sizeof(struct gfs2_log_buf), GFP_NOFS | __GFP_NOFAIL);
-	list_add(&lb->lb_list, &sdp->sd_log_flush_list);
-	lb->lb_real = real;
-
-	bh = lb->lb_bh = alloc_buffer_head(GFP_NOFS | __GFP_NOFAIL);
+	bh = alloc_buffer_head(GFP_NOFS | __GFP_NOFAIL);
 	atomic_set(&bh->b_count, 1);
-	bh->b_state = (1 << BH_Mapped) | (1 << BH_Uptodate);
+	bh->b_state = (1 << BH_Mapped) | (1 << BH_Uptodate) | (1 << BH_Lock);
 	set_bh_page(bh, real->b_page, bh_offset(real));
 	bh->b_blocknr = blkno;
 	bh->b_size = sdp->sd_sb.sb_bsize;
 	bh->b_bdev = sdp->sd_vfs->s_bdev;
+	bh->b_private = real;
+	bh->b_end_io = gfs2_fake_write_endio;
 
-	log_incr_head(sdp);
+	gfs2_log_incr_head(sdp);
+	atomic_inc(&sdp->sd_log_in_flight);
 
 	return bh;
 }
@@ -572,45 +616,75 @@
 		gfs2_assert_withdraw(sdp, !pull);
 
 	sdp->sd_log_idle = (tail == sdp->sd_log_flush_head);
-	log_incr_head(sdp);
+	gfs2_log_incr_head(sdp);
 }
 
 static void log_flush_commit(struct gfs2_sbd *sdp)
 {
-	struct list_head *head = &sdp->sd_log_flush_list;
-	struct gfs2_log_buf *lb;
+	DEFINE_WAIT(wait);
+
+	if (atomic_read(&sdp->sd_log_in_flight)) {
+		do {
+			prepare_to_wait(&sdp->sd_log_flush_wait, &wait,
+					TASK_UNINTERRUPTIBLE);
+			if (atomic_read(&sdp->sd_log_in_flight))
+				io_schedule();
+		} while(atomic_read(&sdp->sd_log_in_flight));
+		finish_wait(&sdp->sd_log_flush_wait, &wait);
+	}
+
+	log_write_header(sdp, 0, 0);
+}
+
+static void gfs2_ordered_write(struct gfs2_sbd *sdp)
+{
+	struct gfs2_bufdata *bd;
 	struct buffer_head *bh;
-	int flushcount = 0;
+	LIST_HEAD(written);
 
-	while (!list_empty(head)) {
-		lb = list_entry(head->next, struct gfs2_log_buf, lb_list);
-		list_del(&lb->lb_list);
-		bh = lb->lb_bh;
-
-		wait_on_buffer(bh);
-		if (!buffer_uptodate(bh))
-			gfs2_io_error_bh(sdp, bh);
-		if (lb->lb_real) {
-			while (atomic_read(&bh->b_count) != 1)  /* Grrrr... */
-				schedule();
-			free_buffer_head(bh);
-		} else
+	gfs2_log_lock(sdp);
+	while (!list_empty(&sdp->sd_log_le_ordered)) {
+		bd = list_entry(sdp->sd_log_le_ordered.next, struct gfs2_bufdata, bd_le.le_list);
+		list_move(&bd->bd_le.le_list, &written);
+		bh = bd->bd_bh;
+		if (!buffer_dirty(bh))
+			continue;
+		get_bh(bh);
+		gfs2_log_unlock(sdp);
+		lock_buffer(bh);
+		if (test_clear_buffer_dirty(bh)) {
+			bh->b_end_io = end_buffer_write_sync;
+			submit_bh(WRITE, bh);
+		} else {
+			unlock_buffer(bh);
 			brelse(bh);
-		kfree(lb);
-		flushcount++;
+		}
+		gfs2_log_lock(sdp);
 	}
+	list_splice(&written, &sdp->sd_log_le_ordered);
+	gfs2_log_unlock(sdp);
+}
 
-	/* If nothing was journaled, the header is unplanned and unwanted. */
-	if (flushcount) {
-		log_write_header(sdp, 0, 0);
-	} else {
-		unsigned int tail;
-		tail = current_tail(sdp);
+static void gfs2_ordered_wait(struct gfs2_sbd *sdp)
+{
+	struct gfs2_bufdata *bd;
+	struct buffer_head *bh;
 
-		gfs2_ail1_empty(sdp, 0);
-		if (sdp->sd_log_tail != tail)
-			log_pull_tail(sdp, tail);
+	gfs2_log_lock(sdp);
+	while (!list_empty(&sdp->sd_log_le_ordered)) {
+		bd = list_entry(sdp->sd_log_le_ordered.prev, struct gfs2_bufdata, bd_le.le_list);
+		bh = bd->bd_bh;
+		if (buffer_locked(bh)) {
+			get_bh(bh);
+			gfs2_log_unlock(sdp);
+			wait_on_buffer(bh);
+			brelse(bh);
+			gfs2_log_lock(sdp);
+			continue;
+		}
+		list_del_init(&bd->bd_le.le_list);
 	}
+	gfs2_log_unlock(sdp);
 }
 
 /**
@@ -640,10 +714,16 @@
 	INIT_LIST_HEAD(&ai->ai_ail1_list);
 	INIT_LIST_HEAD(&ai->ai_ail2_list);
 
-	gfs2_assert_withdraw(sdp,
-			     sdp->sd_log_num_buf + sdp->sd_log_num_jdata ==
-			     sdp->sd_log_commited_buf +
-			     sdp->sd_log_commited_databuf);
+	if (sdp->sd_log_num_buf != sdp->sd_log_commited_buf) {
+		printk(KERN_INFO "GFS2: log buf %u %u\n", sdp->sd_log_num_buf,
+		       sdp->sd_log_commited_buf);
+		gfs2_assert_withdraw(sdp, 0);
+	}
+	if (sdp->sd_log_num_databuf != sdp->sd_log_commited_databuf) {
+		printk(KERN_INFO "GFS2: log databuf %u %u\n",
+		       sdp->sd_log_num_databuf, sdp->sd_log_commited_databuf);
+		gfs2_assert_withdraw(sdp, 0);
+	}
 	gfs2_assert_withdraw(sdp,
 			sdp->sd_log_num_revoke == sdp->sd_log_commited_revoke);
 
@@ -651,8 +731,11 @@
 	sdp->sd_log_flush_wrapped = 0;
 	ai->ai_first = sdp->sd_log_flush_head;
 
+	gfs2_ordered_write(sdp);
 	lops_before_commit(sdp);
-	if (!list_empty(&sdp->sd_log_flush_list))
+	gfs2_ordered_wait(sdp);
+
+	if (sdp->sd_log_head != sdp->sd_log_flush_head)
 		log_flush_commit(sdp);
 	else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle){
 		gfs2_log_lock(sdp);
@@ -744,7 +827,6 @@
 	gfs2_assert_withdraw(sdp, !sdp->sd_log_blks_reserved);
 	gfs2_assert_withdraw(sdp, !sdp->sd_log_num_gl);
 	gfs2_assert_withdraw(sdp, !sdp->sd_log_num_buf);
-	gfs2_assert_withdraw(sdp, !sdp->sd_log_num_jdata);
 	gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke);
 	gfs2_assert_withdraw(sdp, !sdp->sd_log_num_rg);
 	gfs2_assert_withdraw(sdp, !sdp->sd_log_num_databuf);
diff --git a/fs/gfs2/log.h b/fs/gfs2/log.h
index 8e7aa0f..dae2824 100644
--- a/fs/gfs2/log.h
+++ b/fs/gfs2/log.h
@@ -52,12 +52,14 @@
 
 int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks);
 void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks);
+void gfs2_log_incr_head(struct gfs2_sbd *sdp);
 
 struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp);
 struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp,
 				      struct buffer_head *real);
 void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl);
 void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans);
+void gfs2_remove_from_ail(struct address_space *mapping, struct gfs2_bufdata *bd);
 
 void gfs2_log_shutdown(struct gfs2_sbd *sdp);
 void gfs2_meta_syncfs(struct gfs2_sbd *sdp);
diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c
index 3b395c4..6c27cea 100644
--- a/fs/gfs2/lops.c
+++ b/fs/gfs2/lops.c
@@ -27,7 +27,104 @@
 #include "trans.h"
 #include "util.h"
 
-static void glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
+/**
+ * gfs2_pin - Pin a buffer in memory
+ * @sdp: The superblock
+ * @bh: The buffer to be pinned
+ *
+ * The log lock must be held when calling this function
+ */
+static void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh)
+{
+	struct gfs2_bufdata *bd;
+
+	gfs2_assert_withdraw(sdp, test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags));
+
+	clear_buffer_dirty(bh);
+	if (test_set_buffer_pinned(bh))
+		gfs2_assert_withdraw(sdp, 0);
+	if (!buffer_uptodate(bh))
+		gfs2_io_error_bh(sdp, bh);
+	bd = bh->b_private;
+	/* If this buffer is in the AIL and it has already been written
+	 * to in-place disk block, remove it from the AIL.
+	 */
+	if (bd->bd_ail)
+		list_move(&bd->bd_ail_st_list, &bd->bd_ail->ai_ail2_list);
+	get_bh(bh);
+}
+
+/**
+ * gfs2_unpin - Unpin a buffer
+ * @sdp: the filesystem the buffer belongs to
+ * @bh: The buffer to unpin
+ * @ai:
+ *
+ */
+
+static void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh,
+		       struct gfs2_ail *ai)
+{
+	struct gfs2_bufdata *bd = bh->b_private;
+
+	gfs2_assert_withdraw(sdp, buffer_uptodate(bh));
+
+	if (!buffer_pinned(bh))
+		gfs2_assert_withdraw(sdp, 0);
+
+	lock_buffer(bh);
+	mark_buffer_dirty(bh);
+	clear_buffer_pinned(bh);
+
+	gfs2_log_lock(sdp);
+	if (bd->bd_ail) {
+		list_del(&bd->bd_ail_st_list);
+		brelse(bh);
+	} else {
+		struct gfs2_glock *gl = bd->bd_gl;
+		list_add(&bd->bd_ail_gl_list, &gl->gl_ail_list);
+		atomic_inc(&gl->gl_ail_count);
+	}
+	bd->bd_ail = ai;
+	list_add(&bd->bd_ail_st_list, &ai->ai_ail1_list);
+	gfs2_log_unlock(sdp);
+	unlock_buffer(bh);
+}
+
+
+static inline struct gfs2_log_descriptor *bh_log_desc(struct buffer_head *bh)
+{
+	return (struct gfs2_log_descriptor *)bh->b_data;
+}
+
+static inline __be64 *bh_log_ptr(struct buffer_head *bh)
+{
+	struct gfs2_log_descriptor *ld = bh_log_desc(bh);
+	return (__force __be64 *)(ld + 1);
+}
+
+static inline __be64 *bh_ptr_end(struct buffer_head *bh)
+{
+	return (__force __be64 *)(bh->b_data + bh->b_size);
+}
+
+
+static struct buffer_head *gfs2_get_log_desc(struct gfs2_sbd *sdp, u32 ld_type)
+{
+	struct buffer_head *bh = gfs2_log_get_buf(sdp);
+	struct gfs2_log_descriptor *ld = bh_log_desc(bh);
+	ld->ld_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
+	ld->ld_header.mh_type = cpu_to_be32(GFS2_METATYPE_LD);
+	ld->ld_header.mh_format = cpu_to_be32(GFS2_FORMAT_LD);
+	ld->ld_type = cpu_to_be32(ld_type);
+	ld->ld_length = 0;
+	ld->ld_data1 = 0;
+	ld->ld_data2 = 0;
+	memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved));
+	return bh;
+}
+
+static void __glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
 {
 	struct gfs2_glock *gl;
 	struct gfs2_trans *tr = current->journal_info;
@@ -38,15 +135,19 @@
 	if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(gl)))
 		return;
 
-	gfs2_log_lock(sdp);
-	if (!list_empty(&le->le_list)){
-		gfs2_log_unlock(sdp);
+	if (!list_empty(&le->le_list))
 		return;
-	}
+
 	gfs2_glock_hold(gl);
 	set_bit(GLF_DIRTY, &gl->gl_flags);
 	sdp->sd_log_num_gl++;
 	list_add(&le->le_list, &sdp->sd_log_le_gl);
+}
+
+static void glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
+{
+	gfs2_log_lock(sdp);
+	__glock_lo_add(sdp, le);
 	gfs2_log_unlock(sdp);
 }
 
@@ -71,30 +172,25 @@
 	struct gfs2_bufdata *bd = container_of(le, struct gfs2_bufdata, bd_le);
 	struct gfs2_trans *tr;
 
+	lock_buffer(bd->bd_bh);
 	gfs2_log_lock(sdp);
-	if (!list_empty(&bd->bd_list_tr)) {
-		gfs2_log_unlock(sdp);
-		return;
-	}
+	if (!list_empty(&bd->bd_list_tr))
+		goto out;
 	tr = current->journal_info;
 	tr->tr_touched = 1;
 	tr->tr_num_buf++;
 	list_add(&bd->bd_list_tr, &tr->tr_list_buf);
-	gfs2_log_unlock(sdp);
-
 	if (!list_empty(&le->le_list))
-		return;
-
-	gfs2_trans_add_gl(bd->bd_gl);
-
+		goto out;
+	__glock_lo_add(sdp, &bd->bd_gl->gl_le);
 	gfs2_meta_check(sdp, bd->bd_bh);
 	gfs2_pin(sdp, bd->bd_bh);
-	gfs2_log_lock(sdp);
 	sdp->sd_log_num_buf++;
 	list_add(&le->le_list, &sdp->sd_log_le_buf);
-	gfs2_log_unlock(sdp);
-
 	tr->tr_num_buf_new++;
+out:
+	gfs2_log_unlock(sdp);
+	unlock_buffer(bd->bd_bh);
 }
 
 static void buf_lo_incore_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
@@ -117,8 +213,7 @@
 	struct buffer_head *bh;
 	struct gfs2_log_descriptor *ld;
 	struct gfs2_bufdata *bd1 = NULL, *bd2;
-	unsigned int total = sdp->sd_log_num_buf;
-	unsigned int offset = BUF_OFFSET;
+	unsigned int total;
 	unsigned int limit;
 	unsigned int num;
 	unsigned n;
@@ -127,22 +222,20 @@
 	limit = buf_limit(sdp);
 	/* for 4k blocks, limit = 503 */
 
+	gfs2_log_lock(sdp);
+	total = sdp->sd_log_num_buf;
 	bd1 = bd2 = list_prepare_entry(bd1, &sdp->sd_log_le_buf, bd_le.le_list);
 	while(total) {
 		num = total;
 		if (total > limit)
 			num = limit;
-		bh = gfs2_log_get_buf(sdp);
-		ld = (struct gfs2_log_descriptor *)bh->b_data;
-		ptr = (__be64 *)(bh->b_data + offset);
-		ld->ld_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
-		ld->ld_header.mh_type = cpu_to_be32(GFS2_METATYPE_LD);
-		ld->ld_header.mh_format = cpu_to_be32(GFS2_FORMAT_LD);
-		ld->ld_type = cpu_to_be32(GFS2_LOG_DESC_METADATA);
+		gfs2_log_unlock(sdp);
+		bh = gfs2_get_log_desc(sdp, GFS2_LOG_DESC_METADATA);
+		gfs2_log_lock(sdp);
+		ld = bh_log_desc(bh);
+		ptr = bh_log_ptr(bh);
 		ld->ld_length = cpu_to_be32(num + 1);
 		ld->ld_data1 = cpu_to_be32(num);
-		ld->ld_data2 = cpu_to_be32(0);
-		memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved));
 
 		n = 0;
 		list_for_each_entry_continue(bd1, &sdp->sd_log_le_buf,
@@ -152,21 +245,27 @@
 				break;
 		}
 
-		set_buffer_dirty(bh);
-		ll_rw_block(WRITE, 1, &bh);
+		gfs2_log_unlock(sdp);
+		submit_bh(WRITE, bh);
+		gfs2_log_lock(sdp);
 
 		n = 0;
 		list_for_each_entry_continue(bd2, &sdp->sd_log_le_buf,
 					     bd_le.le_list) {
+			get_bh(bd2->bd_bh);
+			gfs2_log_unlock(sdp);
+			lock_buffer(bd2->bd_bh);
 			bh = gfs2_log_fake_buf(sdp, bd2->bd_bh);
-			set_buffer_dirty(bh);
-			ll_rw_block(WRITE, 1, &bh);
+			submit_bh(WRITE, bh);
+			gfs2_log_lock(sdp);
 			if (++n >= num)
 				break;
 		}
 
+		BUG_ON(total < num);
 		total -= num;
 	}
+	gfs2_log_unlock(sdp);
 }
 
 static void buf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
@@ -270,11 +369,8 @@
 	tr = current->journal_info;
 	tr->tr_touched = 1;
 	tr->tr_num_revoke++;
-
-	gfs2_log_lock(sdp);
 	sdp->sd_log_num_revoke++;
 	list_add(&le->le_list, &sdp->sd_log_le_revoke);
-	gfs2_log_unlock(sdp);
 }
 
 static void revoke_lo_before_commit(struct gfs2_sbd *sdp)
@@ -284,32 +380,25 @@
 	struct buffer_head *bh;
 	unsigned int offset;
 	struct list_head *head = &sdp->sd_log_le_revoke;
-	struct gfs2_revoke *rv;
+	struct gfs2_bufdata *bd;
 
 	if (!sdp->sd_log_num_revoke)
 		return;
 
-	bh = gfs2_log_get_buf(sdp);
-	ld = (struct gfs2_log_descriptor *)bh->b_data;
-	ld->ld_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
-	ld->ld_header.mh_type = cpu_to_be32(GFS2_METATYPE_LD);
-	ld->ld_header.mh_format = cpu_to_be32(GFS2_FORMAT_LD);
-	ld->ld_type = cpu_to_be32(GFS2_LOG_DESC_REVOKE);
+	bh = gfs2_get_log_desc(sdp, GFS2_LOG_DESC_REVOKE);
+	ld = bh_log_desc(bh);
 	ld->ld_length = cpu_to_be32(gfs2_struct2blk(sdp, sdp->sd_log_num_revoke,
 						    sizeof(u64)));
 	ld->ld_data1 = cpu_to_be32(sdp->sd_log_num_revoke);
-	ld->ld_data2 = cpu_to_be32(0);
-	memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved));
 	offset = sizeof(struct gfs2_log_descriptor);
 
 	while (!list_empty(head)) {
-		rv = list_entry(head->next, struct gfs2_revoke, rv_le.le_list);
-		list_del_init(&rv->rv_le.le_list);
+		bd = list_entry(head->next, struct gfs2_bufdata, bd_le.le_list);
+		list_del_init(&bd->bd_le.le_list);
 		sdp->sd_log_num_revoke--;
 
 		if (offset + sizeof(u64) > sdp->sd_sb.sb_bsize) {
-			set_buffer_dirty(bh);
-			ll_rw_block(WRITE, 1, &bh);
+			submit_bh(WRITE, bh);
 
 			bh = gfs2_log_get_buf(sdp);
 			mh = (struct gfs2_meta_header *)bh->b_data;
@@ -319,15 +408,14 @@
 			offset = sizeof(struct gfs2_meta_header);
 		}
 
-		*(__be64 *)(bh->b_data + offset) = cpu_to_be64(rv->rv_blkno);
-		kfree(rv);
+		*(__be64 *)(bh->b_data + offset) = cpu_to_be64(bd->bd_blkno);
+		kmem_cache_free(gfs2_bufdata_cachep, bd);
 
 		offset += sizeof(u64);
 	}
 	gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke);
 
-	set_buffer_dirty(bh);
-	ll_rw_block(WRITE, 1, &bh);
+	submit_bh(WRITE, bh);
 }
 
 static void revoke_lo_before_scan(struct gfs2_jdesc *jd,
@@ -466,222 +554,136 @@
 	struct address_space *mapping = bd->bd_bh->b_page->mapping;
 	struct gfs2_inode *ip = GFS2_I(mapping->host);
 
+	lock_buffer(bd->bd_bh);
 	gfs2_log_lock(sdp);
-	if (!list_empty(&bd->bd_list_tr)) {
-		gfs2_log_unlock(sdp);
-		return;
-	}
+	if (!list_empty(&bd->bd_list_tr))
+		goto out;
 	tr->tr_touched = 1;
 	if (gfs2_is_jdata(ip)) {
 		tr->tr_num_buf++;
 		list_add(&bd->bd_list_tr, &tr->tr_list_buf);
 	}
-	gfs2_log_unlock(sdp);
 	if (!list_empty(&le->le_list))
-		return;
+		goto out;
 
-	gfs2_trans_add_gl(bd->bd_gl);
+	__glock_lo_add(sdp, &bd->bd_gl->gl_le);
 	if (gfs2_is_jdata(ip)) {
-		sdp->sd_log_num_jdata++;
 		gfs2_pin(sdp, bd->bd_bh);
 		tr->tr_num_databuf_new++;
+		sdp->sd_log_num_databuf++;
+		list_add(&le->le_list, &sdp->sd_log_le_databuf);
+	} else {
+		list_add(&le->le_list, &sdp->sd_log_le_ordered);
 	}
-	gfs2_log_lock(sdp);
-	sdp->sd_log_num_databuf++;
-	list_add(&le->le_list, &sdp->sd_log_le_databuf);
+out:
 	gfs2_log_unlock(sdp);
+	unlock_buffer(bd->bd_bh);
 }
 
-static int gfs2_check_magic(struct buffer_head *bh)
+static void gfs2_check_magic(struct buffer_head *bh)
 {
-	struct page *page = bh->b_page;
 	void *kaddr;
 	__be32 *ptr;
-	int rv = 0;
 
-	kaddr = kmap_atomic(page, KM_USER0);
+	clear_buffer_escaped(bh);
+	kaddr = kmap_atomic(bh->b_page, KM_USER0);
 	ptr = kaddr + bh_offset(bh);
 	if (*ptr == cpu_to_be32(GFS2_MAGIC))
-		rv = 1;
+		set_buffer_escaped(bh);
 	kunmap_atomic(kaddr, KM_USER0);
+}
 
-	return rv;
+static void gfs2_write_blocks(struct gfs2_sbd *sdp, struct buffer_head *bh,
+			      struct list_head *list, struct list_head *done,
+			      unsigned int n)
+{
+	struct buffer_head *bh1;
+	struct gfs2_log_descriptor *ld;
+	struct gfs2_bufdata *bd;
+	__be64 *ptr;
+
+	if (!bh)
+		return;
+
+	ld = bh_log_desc(bh);
+	ld->ld_length = cpu_to_be32(n + 1);
+	ld->ld_data1 = cpu_to_be32(n);
+
+	ptr = bh_log_ptr(bh);
+	
+	get_bh(bh);
+	submit_bh(WRITE, bh);
+	gfs2_log_lock(sdp);
+	while(!list_empty(list)) {
+		bd = list_entry(list->next, struct gfs2_bufdata, bd_le.le_list);
+		list_move_tail(&bd->bd_le.le_list, done);
+		get_bh(bd->bd_bh);
+		while (be64_to_cpu(*ptr) != bd->bd_bh->b_blocknr) {
+			gfs2_log_incr_head(sdp);
+			ptr += 2;
+		}
+		gfs2_log_unlock(sdp);
+		lock_buffer(bd->bd_bh);
+		if (buffer_escaped(bd->bd_bh)) {
+			void *kaddr;
+			bh1 = gfs2_log_get_buf(sdp);
+			kaddr = kmap_atomic(bd->bd_bh->b_page, KM_USER0);
+			memcpy(bh1->b_data, kaddr + bh_offset(bd->bd_bh),
+			       bh1->b_size);
+			kunmap_atomic(kaddr, KM_USER0);
+			*(__be32 *)bh1->b_data = 0;
+			clear_buffer_escaped(bd->bd_bh);
+			unlock_buffer(bd->bd_bh);
+			brelse(bd->bd_bh);
+		} else {
+			bh1 = gfs2_log_fake_buf(sdp, bd->bd_bh);
+		}
+		submit_bh(WRITE, bh1);
+		gfs2_log_lock(sdp);
+		ptr += 2;
+	}
+	gfs2_log_unlock(sdp);
+	brelse(bh);
 }
 
 /**
  * databuf_lo_before_commit - Scan the data buffers, writing as we go
  *
- * Here we scan through the lists of buffers and make the assumption
- * that any buffer thats been pinned is being journaled, and that
- * any unpinned buffer is an ordered write data buffer and therefore
- * will be written back rather than journaled.
  */
+
 static void databuf_lo_before_commit(struct gfs2_sbd *sdp)
 {
-	LIST_HEAD(started);
-	struct gfs2_bufdata *bd1 = NULL, *bd2, *bdt;
-	struct buffer_head *bh = NULL,*bh1 = NULL;
-	struct gfs2_log_descriptor *ld;
-	unsigned int limit;
-	unsigned int total_dbuf;
-	unsigned int total_jdata = sdp->sd_log_num_jdata;
-	unsigned int num, n;
-	__be64 *ptr = NULL;
+	struct gfs2_bufdata *bd = NULL;
+	struct buffer_head *bh = NULL;
+	unsigned int n = 0;
+	__be64 *ptr = NULL, *end = NULL;
+	LIST_HEAD(processed);
+	LIST_HEAD(in_progress);
 
-	limit = databuf_limit(sdp);
-
-	/*
-	 * Start writing ordered buffers, write journaled buffers
-	 * into the log along with a header
-	 */
 	gfs2_log_lock(sdp);
-	total_dbuf = sdp->sd_log_num_databuf;
-	bd2 = bd1 = list_prepare_entry(bd1, &sdp->sd_log_le_databuf,
-				       bd_le.le_list);
-	while(total_dbuf) {
-		num = total_jdata;
-		if (num > limit)
-			num = limit;
-		n = 0;
-		list_for_each_entry_safe_continue(bd1, bdt,
-						  &sdp->sd_log_le_databuf,
-						  bd_le.le_list) {
-			/* store off the buffer head in a local ptr since
-			 * gfs2_bufdata might change when we drop the log lock
-			 */
-			bh1 = bd1->bd_bh;
-
-			/* An ordered write buffer */
-			if (bh1 && !buffer_pinned(bh1)) {
-				list_move(&bd1->bd_le.le_list, &started);
-				if (bd1 == bd2) {
-					bd2 = NULL;
-					bd2 = list_prepare_entry(bd2,
-							&sdp->sd_log_le_databuf,
-							bd_le.le_list);
-				}
-				total_dbuf--;
-				if (bh1) {
-					if (buffer_dirty(bh1)) {
-						get_bh(bh1);
-
-						gfs2_log_unlock(sdp);
-
-						ll_rw_block(SWRITE, 1, &bh1);
-						brelse(bh1);
-
-						gfs2_log_lock(sdp);
-					}
-					continue;
-				}
-				continue;
-			} else if (bh1) { /* A journaled buffer */
-				int magic;
-				gfs2_log_unlock(sdp);
-				if (!bh) {
-					bh = gfs2_log_get_buf(sdp);
-					ld = (struct gfs2_log_descriptor *)
-					     bh->b_data;
-					ptr = (__be64 *)(bh->b_data +
-							 DATABUF_OFFSET);
-					ld->ld_header.mh_magic =
-						cpu_to_be32(GFS2_MAGIC);
-					ld->ld_header.mh_type =
-						cpu_to_be32(GFS2_METATYPE_LD);
-					ld->ld_header.mh_format =
-						cpu_to_be32(GFS2_FORMAT_LD);
-					ld->ld_type =
-						cpu_to_be32(GFS2_LOG_DESC_JDATA);
-					ld->ld_length = cpu_to_be32(num + 1);
-					ld->ld_data1 = cpu_to_be32(num);
-					ld->ld_data2 = cpu_to_be32(0);
-					memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved));
-				}
-				magic = gfs2_check_magic(bh1);
-				*ptr++ = cpu_to_be64(bh1->b_blocknr);
-				*ptr++ = cpu_to_be64((__u64)magic);
-				clear_buffer_escaped(bh1);
-				if (unlikely(magic != 0))
-					set_buffer_escaped(bh1);
-				gfs2_log_lock(sdp);
-				if (++n >= num)
-					break;
-			} else if (!bh1) {
-				total_dbuf--;
-				sdp->sd_log_num_databuf--;
-				list_del_init(&bd1->bd_le.le_list);
-				if (bd1 == bd2) {
-					bd2 = NULL;
-					bd2 = list_prepare_entry(bd2,
-						&sdp->sd_log_le_databuf,
-						bd_le.le_list);
-                                }
-				kmem_cache_free(gfs2_bufdata_cachep, bd1);
-			}
-		}
-		gfs2_log_unlock(sdp);
-		if (bh) {
-			set_buffer_mapped(bh);
-			set_buffer_dirty(bh);
-			ll_rw_block(WRITE, 1, &bh);
-			bh = NULL;
-		}
-		n = 0;
-		gfs2_log_lock(sdp);
-		list_for_each_entry_continue(bd2, &sdp->sd_log_le_databuf,
-					     bd_le.le_list) {
-			if (!bd2->bd_bh)
-				continue;
-			/* copy buffer if it needs escaping */
+	while (!list_empty(&sdp->sd_log_le_databuf)) {
+		if (ptr == end) {
 			gfs2_log_unlock(sdp);
-			if (unlikely(buffer_escaped(bd2->bd_bh))) {
-				void *kaddr;
-				struct page *page = bd2->bd_bh->b_page;
-				bh = gfs2_log_get_buf(sdp);
-				kaddr = kmap_atomic(page, KM_USER0);
-				memcpy(bh->b_data,
-				       kaddr + bh_offset(bd2->bd_bh),
-				       sdp->sd_sb.sb_bsize);
-				kunmap_atomic(kaddr, KM_USER0);
-				*(__be32 *)bh->b_data = 0;
-			} else {
-				bh = gfs2_log_fake_buf(sdp, bd2->bd_bh);
-			}
-			set_buffer_dirty(bh);
-			ll_rw_block(WRITE, 1, &bh);
+			gfs2_write_blocks(sdp, bh, &in_progress, &processed, n);
+			n = 0;
+			bh = gfs2_get_log_desc(sdp, GFS2_LOG_DESC_JDATA);
+			ptr = bh_log_ptr(bh);
+			end = bh_ptr_end(bh) - 1;
 			gfs2_log_lock(sdp);
-			if (++n >= num)
-				break;
+			continue;
 		}
-		bh = NULL;
-		BUG_ON(total_dbuf < num);
-		total_dbuf -= num;
-		total_jdata -= num;
+		bd = list_entry(sdp->sd_log_le_databuf.next, struct gfs2_bufdata, bd_le.le_list);
+		list_move_tail(&bd->bd_le.le_list, &in_progress);
+		gfs2_check_magic(bd->bd_bh);
+		*ptr++ = cpu_to_be64(bd->bd_bh->b_blocknr);
+		*ptr++ = cpu_to_be64(buffer_escaped(bh) ? 1 : 0);
+		n++;
 	}
 	gfs2_log_unlock(sdp);
-
-	/* Wait on all ordered buffers */
-	while (!list_empty(&started)) {
-		gfs2_log_lock(sdp);
-		bd1 = list_entry(started.next, struct gfs2_bufdata,
-				 bd_le.le_list);
-		list_del_init(&bd1->bd_le.le_list);
-		sdp->sd_log_num_databuf--;
-		bh = bd1->bd_bh;
-		if (bh) {
-			bh->b_private = NULL;
-			get_bh(bh);
-			gfs2_log_unlock(sdp);
-			wait_on_buffer(bh);
-			brelse(bh);
-		} else
-			gfs2_log_unlock(sdp);
-
-		kmem_cache_free(gfs2_bufdata_cachep, bd1);
-	}
-
-	/* We've removed all the ordered write bufs here, so only jdata left */
-	gfs2_assert_warn(sdp, sdp->sd_log_num_databuf == sdp->sd_log_num_jdata);
+	gfs2_write_blocks(sdp, bh, &in_progress, &processed, n);
+	gfs2_log_lock(sdp);
+	list_splice(&processed, &sdp->sd_log_le_databuf);
+	gfs2_log_unlock(sdp);
 }
 
 static int databuf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start,
@@ -765,11 +767,9 @@
 		bd = list_entry(head->next, struct gfs2_bufdata, bd_le.le_list);
 		list_del_init(&bd->bd_le.le_list);
 		sdp->sd_log_num_databuf--;
-		sdp->sd_log_num_jdata--;
 		gfs2_unpin(sdp, bd->bd_bh, ai);
 	}
 	gfs2_assert_warn(sdp, !sdp->sd_log_num_databuf);
-	gfs2_assert_warn(sdp, !sdp->sd_log_num_jdata);
 }
 
 
@@ -817,10 +817,10 @@
 
 const struct gfs2_log_operations *gfs2_log_ops[] = {
 	&gfs2_glock_lops,
-	&gfs2_buf_lops,
-	&gfs2_revoke_lops,
-	&gfs2_rg_lops,
 	&gfs2_databuf_lops,
+	&gfs2_buf_lops,
+	&gfs2_rg_lops,
+	&gfs2_revoke_lops,
 	NULL,
 };
 
diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c
index d5d4e68..79c91fd 100644
--- a/fs/gfs2/main.c
+++ b/fs/gfs2/main.c
@@ -107,6 +107,8 @@
 fail_unregister:
 	unregister_filesystem(&gfs2_fs_type);
 fail:
+	gfs2_glock_exit();
+
 	if (gfs2_bufdata_cachep)
 		kmem_cache_destroy(gfs2_bufdata_cachep);
 
@@ -127,6 +129,7 @@
 
 static void __exit exit_gfs2_fs(void)
 {
+	gfs2_glock_exit();
 	gfs2_unregister_debugfs();
 	unregister_filesystem(&gfs2_fs_type);
 	unregister_filesystem(&gfs2meta_fs_type);
diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c
index 8da343b..4da4239 100644
--- a/fs/gfs2/meta_io.c
+++ b/fs/gfs2/meta_io.c
@@ -297,74 +297,35 @@
 		unlock_page(bh->b_page);
 }
 
-/**
- * gfs2_pin - Pin a buffer in memory
- * @sdp: the filesystem the buffer belongs to
- * @bh: The buffer to be pinned
- *
- */
-
-void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh)
+void gfs2_remove_from_journal(struct buffer_head *bh, struct gfs2_trans *tr, int meta)
 {
+	struct gfs2_sbd *sdp = GFS2_SB(bh->b_page->mapping->host);
 	struct gfs2_bufdata *bd = bh->b_private;
-
-	gfs2_assert_withdraw(sdp, test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags));
-
-	if (test_set_buffer_pinned(bh))
-		gfs2_assert_withdraw(sdp, 0);
-
-	wait_on_buffer(bh);
-
-	/* If this buffer is in the AIL and it has already been written
-	   to in-place disk block, remove it from the AIL. */
-
-	gfs2_log_lock(sdp);
-	if (bd->bd_ail && !buffer_in_io(bh))
-		list_move(&bd->bd_ail_st_list, &bd->bd_ail->ai_ail2_list);
-	gfs2_log_unlock(sdp);
-
-	clear_buffer_dirty(bh);
-	wait_on_buffer(bh);
-
-	if (!buffer_uptodate(bh))
-		gfs2_io_error_bh(sdp, bh);
-
-	get_bh(bh);
-}
-
-/**
- * gfs2_unpin - Unpin a buffer
- * @sdp: the filesystem the buffer belongs to
- * @bh: The buffer to unpin
- * @ai:
- *
- */
-
-void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh,
-	        struct gfs2_ail *ai)
-{
-	struct gfs2_bufdata *bd = bh->b_private;
-
-	gfs2_assert_withdraw(sdp, buffer_uptodate(bh));
-
-	if (!buffer_pinned(bh))
-		gfs2_assert_withdraw(sdp, 0);
-
-	mark_buffer_dirty(bh);
-	clear_buffer_pinned(bh);
-
-	gfs2_log_lock(sdp);
-	if (bd->bd_ail) {
-		list_del(&bd->bd_ail_st_list);
+	if (test_clear_buffer_pinned(bh)) {
+		list_del_init(&bd->bd_le.le_list);
+		if (meta) {
+			gfs2_assert_warn(sdp, sdp->sd_log_num_buf);
+			sdp->sd_log_num_buf--;
+			tr->tr_num_buf_rm++;
+		} else {
+			gfs2_assert_warn(sdp, sdp->sd_log_num_databuf);
+			sdp->sd_log_num_databuf--;
+			tr->tr_num_databuf_rm++;
+		}
+		tr->tr_touched = 1;
 		brelse(bh);
-	} else {
-		struct gfs2_glock *gl = bd->bd_gl;
-		list_add(&bd->bd_ail_gl_list, &gl->gl_ail_list);
-		atomic_inc(&gl->gl_ail_count);
 	}
-	bd->bd_ail = ai;
-	list_add(&bd->bd_ail_st_list, &ai->ai_ail1_list);
-	gfs2_log_unlock(sdp);
+	if (bd) {
+		if (bd->bd_ail) {
+			gfs2_remove_from_ail(NULL, bd);
+			bh->b_private = NULL;
+			bd->bd_bh = NULL;
+			bd->bd_blkno = bh->b_blocknr;
+			gfs2_trans_add_revoke(sdp, bd);
+		}
+	}
+	clear_buffer_dirty(bh);
+	clear_buffer_uptodate(bh);
 }
 
 /**
@@ -383,44 +344,11 @@
 	while (blen) {
 		bh = getbuf(ip->i_gl, bstart, NO_CREATE);
 		if (bh) {
-			struct gfs2_bufdata *bd = bh->b_private;
-
-			if (test_clear_buffer_pinned(bh)) {
-				struct gfs2_trans *tr = current->journal_info;
-				struct gfs2_inode *bh_ip =
-					GFS2_I(bh->b_page->mapping->host);
-
-				gfs2_log_lock(sdp);
-				list_del_init(&bd->bd_le.le_list);
-				gfs2_assert_warn(sdp, sdp->sd_log_num_buf);
-				sdp->sd_log_num_buf--;
-				gfs2_log_unlock(sdp);
-				if (bh_ip->i_inode.i_private != NULL)
-					tr->tr_num_databuf_rm++;
-				else
-					tr->tr_num_buf_rm++;
-				brelse(bh);
-			}
-			if (bd) {
-				gfs2_log_lock(sdp);
-				if (bd->bd_ail) {
-					u64 blkno = bh->b_blocknr;
-					bd->bd_ail = NULL;
-					list_del(&bd->bd_ail_st_list);
-					list_del(&bd->bd_ail_gl_list);
-					atomic_dec(&bd->bd_gl->gl_ail_count);
-					brelse(bh);
-					gfs2_log_unlock(sdp);
-					gfs2_trans_add_revoke(sdp, blkno);
-				} else
-					gfs2_log_unlock(sdp);
-			}
-
 			lock_buffer(bh);
-			clear_buffer_dirty(bh);
-			clear_buffer_uptodate(bh);
+			gfs2_log_lock(sdp);
+			gfs2_remove_from_journal(bh, current->journal_info, 1);
+			gfs2_log_unlock(sdp);
 			unlock_buffer(bh);
-
 			brelse(bh);
 		}
 
@@ -446,10 +374,10 @@
 
 	for (x = 0; x < GFS2_MAX_META_HEIGHT; x++) {
 		bh_slot = &ip->i_cache[x];
-		if (!*bh_slot)
-			break;
-		brelse(*bh_slot);
-		*bh_slot = NULL;
+		if (*bh_slot) {
+			brelse(*bh_slot);
+			*bh_slot = NULL;
+		}
 	}
 
 	spin_unlock(&ip->i_spin);
diff --git a/fs/gfs2/meta_io.h b/fs/gfs2/meta_io.h
index 527bf19..b704822 100644
--- a/fs/gfs2/meta_io.h
+++ b/fs/gfs2/meta_io.h
@@ -50,9 +50,9 @@
 
 void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh,
 			 int meta);
-void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh);
-void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh,
-		struct gfs2_ail *ai);
+
+void gfs2_remove_from_journal(struct buffer_head *bh, struct gfs2_trans *tr,
+			      int meta);
 
 void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen);
 
diff --git a/fs/gfs2/mount.c b/fs/gfs2/mount.c
index 4864659..b941f9f 100644
--- a/fs/gfs2/mount.c
+++ b/fs/gfs2/mount.c
@@ -42,6 +42,7 @@
 	Opt_nosuiddir,
 	Opt_data_writeback,
 	Opt_data_ordered,
+	Opt_err,
 };
 
 static match_table_t tokens = {
@@ -64,7 +65,8 @@
 	{Opt_suiddir, "suiddir"},
 	{Opt_nosuiddir, "nosuiddir"},
 	{Opt_data_writeback, "data=writeback"},
-	{Opt_data_ordered, "data=ordered"}
+	{Opt_data_ordered, "data=ordered"},
+	{Opt_err, NULL}
 };
 
 /**
@@ -237,6 +239,7 @@
 		case Opt_data_ordered:
 			args->ar_data = GFS2_DATA_ORDERED;
 			break;
+		case Opt_err:
 		default:
 			fs_info(sdp, "unknown option: %s\n", o);
 			error = -EINVAL;
diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c
index 42a5f58..873a511 100644
--- a/fs/gfs2/ops_address.c
+++ b/fs/gfs2/ops_address.c
@@ -90,7 +90,7 @@
 	error = gfs2_block_map(inode, lblock, 0, bh_result);
 	if (error)
 		return error;
-	if (bh_result->b_blocknr == 0)
+	if (!buffer_mapped(bh_result))
 		return -EIO;
 	return 0;
 }
@@ -414,7 +414,8 @@
 	if (ind_blocks || data_blocks)
 		rblocks += RES_STATFS + RES_QUOTA;
 
-	error = gfs2_trans_begin(sdp, rblocks, 0);
+	error = gfs2_trans_begin(sdp, rblocks,
+				 PAGE_CACHE_SIZE/sdp->sd_sb.sb_bsize);
 	if (error)
 		goto out_trans_fail;
 
@@ -616,58 +617,50 @@
 	return dblock;
 }
 
-static void discard_buffer(struct gfs2_sbd *sdp, struct buffer_head *bh)
+static void gfs2_discard(struct gfs2_sbd *sdp, struct buffer_head *bh)
 {
 	struct gfs2_bufdata *bd;
 
+	lock_buffer(bh);
 	gfs2_log_lock(sdp);
+	clear_buffer_dirty(bh);
 	bd = bh->b_private;
 	if (bd) {
-		bd->bd_bh = NULL;
-		bh->b_private = NULL;
-		if (!bd->bd_ail && list_empty(&bd->bd_le.le_list))
-			kmem_cache_free(gfs2_bufdata_cachep, bd);
+		if (!list_empty(&bd->bd_le.le_list) && !buffer_pinned(bh))
+			list_del_init(&bd->bd_le.le_list);
+		else
+			gfs2_remove_from_journal(bh, current->journal_info, 0);
 	}
-	gfs2_log_unlock(sdp);
-
-	lock_buffer(bh);
-	clear_buffer_dirty(bh);
 	bh->b_bdev = NULL;
 	clear_buffer_mapped(bh);
 	clear_buffer_req(bh);
 	clear_buffer_new(bh);
-	clear_buffer_delay(bh);
+	gfs2_log_unlock(sdp);
 	unlock_buffer(bh);
 }
 
 static void gfs2_invalidatepage(struct page *page, unsigned long offset)
 {
 	struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host);
-	struct buffer_head *head, *bh, *next;
-	unsigned int curr_off = 0;
+	struct buffer_head *bh, *head;
+	unsigned long pos = 0;
 
 	BUG_ON(!PageLocked(page));
 	if (offset == 0)
 		ClearPageChecked(page);
 	if (!page_has_buffers(page))
-		return;
+		goto out;
 
 	bh = head = page_buffers(page);
 	do {
-		unsigned int next_off = curr_off + bh->b_size;
-		next = bh->b_this_page;
-
-		if (offset <= curr_off)
-			discard_buffer(sdp, bh);
-
-		curr_off = next_off;
-		bh = next;
+		if (offset <= pos)
+			gfs2_discard(sdp, bh);
+		pos += bh->b_size;
+		bh = bh->b_this_page;
 	} while (bh != head);
-
-	if (!offset)
+out:
+	if (offset == 0)
 		try_to_release_page(page, 0);
-
-	return;
 }
 
 /**
@@ -736,59 +729,6 @@
 }
 
 /**
- * stuck_releasepage - We're stuck in gfs2_releasepage().  Print stuff out.
- * @bh: the buffer we're stuck on
- *
- */
-
-static void stuck_releasepage(struct buffer_head *bh)
-{
-	struct inode *inode = bh->b_page->mapping->host;
-	struct gfs2_sbd *sdp = inode->i_sb->s_fs_info;
-	struct gfs2_bufdata *bd = bh->b_private;
-	struct gfs2_glock *gl;
-static unsigned limit = 0;
-
-	if (limit > 3)
-		return;
-	limit++;
-
-	fs_warn(sdp, "stuck in gfs2_releasepage() %p\n", inode);
-	fs_warn(sdp, "blkno = %llu, bh->b_count = %d\n",
-		(unsigned long long)bh->b_blocknr, atomic_read(&bh->b_count));
-	fs_warn(sdp, "pinned = %u\n", buffer_pinned(bh));
-	fs_warn(sdp, "bh->b_private = %s\n", (bd) ? "!NULL" : "NULL");
-
-	if (!bd)
-		return;
-
-	gl = bd->bd_gl;
-
-	fs_warn(sdp, "gl = (%u, %llu)\n",
-		gl->gl_name.ln_type, (unsigned long long)gl->gl_name.ln_number);
-
-	fs_warn(sdp, "bd_list_tr = %s, bd_le.le_list = %s\n",
-		(list_empty(&bd->bd_list_tr)) ? "no" : "yes",
-		(list_empty(&bd->bd_le.le_list)) ? "no" : "yes");
-
-	if (gl->gl_ops == &gfs2_inode_glops) {
-		struct gfs2_inode *ip = gl->gl_object;
-		unsigned int x;
-
-		if (!ip)
-			return;
-
-		fs_warn(sdp, "ip = %llu %llu\n",
-			(unsigned long long)ip->i_no_formal_ino,
-			(unsigned long long)ip->i_no_addr);
-
-		for (x = 0; x < GFS2_MAX_META_HEIGHT; x++)
-			fs_warn(sdp, "ip->i_cache[%u] = %s\n",
-				x, (ip->i_cache[x]) ? "!NULL" : "NULL");
-	}
-}
-
-/**
  * gfs2_releasepage - free the metadata associated with a page
  * @page: the page that's being released
  * @gfp_mask: passed from Linux VFS, ignored by us
@@ -805,41 +745,39 @@
 	struct gfs2_sbd *sdp = aspace->i_sb->s_fs_info;
 	struct buffer_head *bh, *head;
 	struct gfs2_bufdata *bd;
-	unsigned long t = jiffies + gfs2_tune_get(sdp, gt_stall_secs) * HZ;
 
 	if (!page_has_buffers(page))
-		goto out;
+		return 0;
+
+	gfs2_log_lock(sdp);
+	head = bh = page_buffers(page);
+	do {
+		if (atomic_read(&bh->b_count))
+			goto cannot_release;
+		bd = bh->b_private;
+		if (bd && bd->bd_ail)
+			goto cannot_release;
+		gfs2_assert_warn(sdp, !buffer_pinned(bh));
+		gfs2_assert_warn(sdp, !buffer_dirty(bh));
+		bh = bh->b_this_page;
+	} while(bh != head);
+	gfs2_log_unlock(sdp);
 
 	head = bh = page_buffers(page);
 	do {
-		while (atomic_read(&bh->b_count)) {
-			if (!atomic_read(&aspace->i_writecount))
-				return 0;
-
-			if (!(gfp_mask & __GFP_WAIT))
-				return 0;
-
-			if (time_after_eq(jiffies, t)) {
-				stuck_releasepage(bh);
-				/* should we withdraw here? */
-				return 0;
-			}
-
-			yield();
-		}
-
-		gfs2_assert_warn(sdp, !buffer_pinned(bh));
-		gfs2_assert_warn(sdp, !buffer_dirty(bh));
-
 		gfs2_log_lock(sdp);
 		bd = bh->b_private;
 		if (bd) {
 			gfs2_assert_warn(sdp, bd->bd_bh == bh);
 			gfs2_assert_warn(sdp, list_empty(&bd->bd_list_tr));
-			gfs2_assert_warn(sdp, !bd->bd_ail);
-			bd->bd_bh = NULL;
-			if (!list_empty(&bd->bd_le.le_list))
-				bd = NULL;
+			if (!list_empty(&bd->bd_le.le_list)) {
+				if (!buffer_pinned(bh))
+					list_del_init(&bd->bd_le.le_list);
+				else
+					bd = NULL;
+			}
+			if (bd)
+				bd->bd_bh = NULL;
 			bh->b_private = NULL;
 		}
 		gfs2_log_unlock(sdp);
@@ -849,8 +787,10 @@
 		bh = bh->b_this_page;
 	} while (bh != head);
 
-out:
 	return try_to_free_buffers(page);
+cannot_release:
+	gfs2_log_unlock(sdp);
+	return 0;
 }
 
 const struct address_space_operations gfs2_file_aops = {
diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c
index b8312ed..e2d1347 100644
--- a/fs/gfs2/ops_export.c
+++ b/fs/gfs2/ops_export.c
@@ -237,7 +237,7 @@
 
 	inode = gfs2_inode_lookup(sb, DT_UNKNOWN,
 					inum->no_addr,
-					0);
+					0, 0);
 	if (!inode)
 		goto fail;
 	if (IS_ERR(inode)) {
diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c
index 94d76ac..46a9e10 100644
--- a/fs/gfs2/ops_file.c
+++ b/fs/gfs2/ops_file.c
@@ -571,7 +571,8 @@
 	int error = 0;
 
 	state = (fl->fl_type == F_WRLCK) ? LM_ST_EXCLUSIVE : LM_ST_SHARED;
-	flags = (IS_SETLKW(cmd) ? 0 : LM_FLAG_TRY) | GL_EXACT | GL_NOCACHE;
+	flags = (IS_SETLKW(cmd) ? 0 : LM_FLAG_TRY) | GL_EXACT | GL_NOCACHE 
+		| GL_FLOCK;
 
 	mutex_lock(&fp->f_fl_mutex);
 
@@ -579,21 +580,19 @@
 	if (gl) {
 		if (fl_gh->gh_state == state)
 			goto out;
-		gfs2_glock_hold(gl);
 		flock_lock_file_wait(file,
 				     &(struct file_lock){.fl_type = F_UNLCK});
-		gfs2_glock_dq_uninit(fl_gh);
+		gfs2_glock_dq_wait(fl_gh);
+		gfs2_holder_reinit(state, flags, fl_gh);
 	} else {
 		error = gfs2_glock_get(GFS2_SB(&ip->i_inode),
 				      ip->i_no_addr, &gfs2_flock_glops,
 				      CREATE, &gl);
 		if (error)
 			goto out;
+		gfs2_holder_init(gl, state, flags, fl_gh);
+		gfs2_glock_put(gl);
 	}
-
-	gfs2_holder_init(gl, state, flags, fl_gh);
-	gfs2_glock_put(gl);
-
 	error = gfs2_glock_nq(fl_gh);
 	if (error) {
 		gfs2_holder_uninit(fl_gh);
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index cf5aa50..17de58e 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -28,18 +28,18 @@
 #include "lm.h"
 #include "mount.h"
 #include "ops_fstype.h"
+#include "ops_dentry.h"
 #include "ops_super.h"
 #include "recovery.h"
 #include "rgrp.h"
 #include "super.h"
 #include "sys.h"
 #include "util.h"
+#include "log.h"
 
 #define DO 0
 #define UNDO 1
 
-extern struct dentry_operations gfs2_dops;
-
 static struct gfs2_sbd *init_sbd(struct super_block *sb)
 {
 	struct gfs2_sbd *sdp;
@@ -82,13 +82,15 @@
 	INIT_LIST_HEAD(&sdp->sd_log_le_revoke);
 	INIT_LIST_HEAD(&sdp->sd_log_le_rg);
 	INIT_LIST_HEAD(&sdp->sd_log_le_databuf);
+	INIT_LIST_HEAD(&sdp->sd_log_le_ordered);
 
 	mutex_init(&sdp->sd_log_reserve_mutex);
 	INIT_LIST_HEAD(&sdp->sd_ail1_list);
 	INIT_LIST_HEAD(&sdp->sd_ail2_list);
 
 	init_rwsem(&sdp->sd_log_flush_lock);
-	INIT_LIST_HEAD(&sdp->sd_log_flush_list);
+	atomic_set(&sdp->sd_log_in_flight, 0);
+	init_waitqueue_head(&sdp->sd_log_flush_wait);
 
 	INIT_LIST_HEAD(&sdp->sd_revoke_list);
 
@@ -145,7 +147,8 @@
 	snprintf(sdp->sd_proto_name, GFS2_FSNAME_LEN, "%s", proto);
 	snprintf(sdp->sd_table_name, GFS2_FSNAME_LEN, "%s", table);
 
-	while ((table = strchr(sdp->sd_table_name, '/')))
+	table = sdp->sd_table_name;
+	while ((table = strchr(table, '/')))
 		*table = '_';
 
 out:
@@ -161,14 +164,6 @@
 	if (undo)
 		goto fail_trans;
 
-	p = kthread_run(gfs2_scand, sdp, "gfs2_scand");
-	error = IS_ERR(p);
-	if (error) {
-		fs_err(sdp, "can't start scand thread: %d\n", error);
-		return error;
-	}
-	sdp->sd_scand_process = p;
-
 	for (sdp->sd_glockd_num = 0;
 	     sdp->sd_glockd_num < sdp->sd_args.ar_num_glockd;
 	     sdp->sd_glockd_num++) {
@@ -229,14 +224,13 @@
 	while (sdp->sd_glockd_num--)
 		kthread_stop(sdp->sd_glockd_process[sdp->sd_glockd_num]);
 
-	kthread_stop(sdp->sd_scand_process);
 	return error;
 }
 
 static inline struct inode *gfs2_lookup_root(struct super_block *sb,
 					     u64 no_addr)
 {
-	return gfs2_inode_lookup(sb, DT_DIR, no_addr, 0);
+	return gfs2_inode_lookup(sb, DT_DIR, no_addr, 0, 0);
 }
 
 static int init_sb(struct gfs2_sbd *sdp, int silent, int undo)
@@ -301,8 +295,9 @@
 		fs_err(sdp, "can't get root dentry\n");
 		error = -ENOMEM;
 		iput(inode);
-	}
-	sb->s_root->d_op = &gfs2_dops;
+	} else
+		sb->s_root->d_op = &gfs2_dops;
+	
 out:
 	gfs2_glock_dq_uninit(&sb_gh);
 	return error;
@@ -368,7 +363,7 @@
 
 		ip = GFS2_I(sdp->sd_jdesc->jd_inode);
 		error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED,
-					   LM_FLAG_NOEXP | GL_EXACT,
+					   LM_FLAG_NOEXP | GL_EXACT | GL_NOCACHE,
 					   &sdp->sd_jinode_gh);
 		if (error) {
 			fs_err(sdp, "can't acquire journal inode glock: %d\n",
@@ -818,7 +813,6 @@
 	struct nameidata nd;
 	struct file_system_type *fstype;
 	struct super_block *sb = NULL, *s;
-	struct list_head *l;
 	int error;
 
 	error = path_lookup(dev_name, LOOKUP_FOLLOW, &nd);
@@ -830,8 +824,7 @@
 	error = vfs_getattr(nd.mnt, nd.dentry, &stat);
 
 	fstype = get_fs_type("gfs2");
-	list_for_each(l, &fstype->fs_supers) {
-		s = list_entry(l, struct super_block, s_instances);
+	list_for_each_entry(s, &fstype->fs_supers, s_instances) {
 		if ((S_ISBLK(stat.mode) && s->s_dev == stat.rdev) ||
 		    (S_ISDIR(stat.mode) && s == nd.dentry->d_inode->i_sb)) {
 			sb = s;
@@ -861,7 +854,7 @@
 		error = -ENOENT;
 		goto error;
 	}
-	sdp = (struct gfs2_sbd*) sb->s_fs_info;
+	sdp = sb->s_fs_info;
 	if (sdp->sd_vfs_meta) {
 		printk(KERN_WARNING "GFS2: gfs2meta mount already exists\n");
 		error = -EBUSY;
@@ -896,7 +889,10 @@
 
 static void gfs2_kill_sb(struct super_block *sb)
 {
-	gfs2_delete_debugfs_file(sb->s_fs_info);
+	if (sb->s_fs_info) {
+		gfs2_delete_debugfs_file(sb->s_fs_info);
+		gfs2_meta_syncfs(sb->s_fs_info);
+	}
 	kill_block_super(sb);
 }
 
diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c
index 911c115..291f0c7 100644
--- a/fs/gfs2/ops_inode.c
+++ b/fs/gfs2/ops_inode.c
@@ -69,7 +69,7 @@
 			mark_inode_dirty(inode);
 			break;
 		} else if (PTR_ERR(inode) != -EEXIST ||
-			   (nd->intent.open.flags & O_EXCL)) {
+			   (nd && (nd->intent.open.flags & O_EXCL))) {
 			gfs2_holder_uninit(ghs);
 			return PTR_ERR(inode);
 		}
@@ -278,17 +278,25 @@
 	gfs2_holder_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + 2);
 
 
-	error = gfs2_glock_nq_m(3, ghs);
+	error = gfs2_glock_nq(ghs); /* parent */
 	if (error)
-		goto out;
+		goto out_parent;
+
+	error = gfs2_glock_nq(ghs + 1); /* child */
+	if (error)
+		goto out_child;
+
+	error = gfs2_glock_nq(ghs + 2); /* rgrp */
+	if (error)
+		goto out_rgrp;
 
 	error = gfs2_unlink_ok(dip, &dentry->d_name, ip);
 	if (error)
-		goto out_gunlock;
+		goto out_rgrp;
 
 	error = gfs2_trans_begin(sdp, 2*RES_DINODE + RES_LEAF + RES_RG_BIT, 0);
 	if (error)
-		goto out_gunlock;
+		goto out_rgrp;
 
 	error = gfs2_dir_del(dip, &dentry->d_name);
         if (error)
@@ -298,12 +306,15 @@
 
 out_end_trans:
 	gfs2_trans_end(sdp);
-out_gunlock:
-	gfs2_glock_dq_m(3, ghs);
-out:
-	gfs2_holder_uninit(ghs);
-	gfs2_holder_uninit(ghs + 1);
+	gfs2_glock_dq(ghs + 2);
+out_rgrp:
 	gfs2_holder_uninit(ghs + 2);
+	gfs2_glock_dq(ghs + 1);
+out_child:
+	gfs2_holder_uninit(ghs + 1);
+	gfs2_glock_dq(ghs);
+out_parent:
+	gfs2_holder_uninit(ghs);
 	gfs2_glock_dq_uninit(&ri_gh);
 	return error;
 }
@@ -894,12 +905,17 @@
 static int setattr_size(struct inode *inode, struct iattr *attr)
 {
 	struct gfs2_inode *ip = GFS2_I(inode);
+	struct gfs2_sbd *sdp = GFS2_SB(inode);
 	int error;
 
 	if (attr->ia_size != ip->i_di.di_size) {
-		error = vmtruncate(inode, attr->ia_size);
+		error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks);
 		if (error)
 			return error;
+		error = vmtruncate(inode, attr->ia_size);
+		gfs2_trans_end(sdp);
+		if (error) 
+			return error;
 	}
 
 	error = gfs2_truncatei(ip, attr->ia_size);
diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c
index 603d940..950f314 100644
--- a/fs/gfs2/ops_super.c
+++ b/fs/gfs2/ops_super.c
@@ -92,7 +92,6 @@
 	kthread_stop(sdp->sd_recoverd_process);
 	while (sdp->sd_glockd_num--)
 		kthread_stop(sdp->sd_glockd_process[sdp->sd_glockd_num]);
-	kthread_stop(sdp->sd_scand_process);
 
 	if (!(sb->s_flags & MS_RDONLY)) {
 		error = gfs2_make_fs_ro(sdp);
@@ -456,12 +455,15 @@
 	}
 
 	error = gfs2_dinode_dealloc(ip);
-	/*
-	 * Must do this before unlock to avoid trying to write back
-	 * potentially dirty data now that inode no longer exists
-	 * on disk.
-	 */
+	if (error)
+		goto out_unlock;
+
+	error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks);
+	if (error)
+		goto out_unlock;
+	/* Needs to be done before glock release & also in a transaction */
 	truncate_inode_pages(&inode->i_data, 0);
+	gfs2_trans_end(sdp);
 
 out_unlock:
 	gfs2_glock_dq(&ip->i_iopen_gh);
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
index 6e546ee..addb51e 100644
--- a/fs/gfs2/quota.c
+++ b/fs/gfs2/quota.c
@@ -70,6 +70,7 @@
 	u64 qu_limit;
 	u64 qu_warn;
 	s64 qu_value;
+	u32 qu_ll_next;
 };
 
 struct gfs2_quota_change_host {
@@ -580,6 +581,7 @@
 	qu->qu_limit = be64_to_cpu(str->qu_limit);
 	qu->qu_warn = be64_to_cpu(str->qu_warn);
 	qu->qu_value = be64_to_cpu(str->qu_value);
+	qu->qu_ll_next = be32_to_cpu(str->qu_ll_next);
 }
 
 static void gfs2_quota_out(const struct gfs2_quota_host *qu, void *buf)
@@ -589,6 +591,7 @@
 	str->qu_limit = cpu_to_be64(qu->qu_limit);
 	str->qu_warn = cpu_to_be64(qu->qu_warn);
 	str->qu_value = cpu_to_be64(qu->qu_value);
+	str->qu_ll_next = cpu_to_be32(qu->qu_ll_next);
 	memset(&str->qu_reserved, 0, sizeof(str->qu_reserved));
 }
 
@@ -614,6 +617,16 @@
 	s64 value;
 	int err = -EIO;
 
+	if (gfs2_is_stuffed(ip)) {
+		struct gfs2_alloc *al = NULL;
+		al = gfs2_alloc_get(ip);
+		/* just request 1 blk */
+		al->al_requested = 1;
+		gfs2_inplace_reserve(ip);
+		gfs2_unstuff_dinode(ip, NULL);
+		gfs2_inplace_release(ip);
+		gfs2_alloc_put(ip);
+	}
 	page = grab_cache_page(mapping, index);
 	if (!page)
 		return -ENOMEM;
diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c
index 5ada38c..beb6c7a 100644
--- a/fs/gfs2/recovery.c
+++ b/fs/gfs2/recovery.c
@@ -469,7 +469,7 @@
 		};
 
 		error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED,
-					   LM_FLAG_NOEXP, &ji_gh);
+					   LM_FLAG_NOEXP | GL_NOCACHE, &ji_gh);
 		if (error)
 			goto fail_gunlock_j;
 	} else {
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c
index ce48c45..708c287 100644
--- a/fs/gfs2/rgrp.c
+++ b/fs/gfs2/rgrp.c
@@ -31,6 +31,7 @@
 #include "inode.h"
 
 #define BFITNOENT ((u32)~0)
+#define NO_BLOCK ((u64)~0)
 
 /*
  * These routines are used by the resource group routines (rgrp.c)
@@ -116,8 +117,7 @@
  * @buffer: the buffer that holds the bitmaps
  * @buflen: the length (in bytes) of the buffer
  * @goal: start search at this block's bit-pair (within @buffer)
- * @old_state: GFS2_BLKST_XXX the state of the block we're looking for;
- *       bit 0 = alloc(1)/free(0), bit 1 = meta(1)/data(0)
+ * @old_state: GFS2_BLKST_XXX the state of the block we're looking for.
  *
  * Scope of @goal and returned block number is only within this bitmap buffer,
  * not entire rgrp or filesystem.  @buffer will be offset from the actual
@@ -137,9 +137,13 @@
 	byte = buffer + (goal / GFS2_NBBY);
 	bit = (goal % GFS2_NBBY) * GFS2_BIT_SIZE;
 	end = buffer + buflen;
-	alloc = (old_state & 1) ? 0 : 0x55;
+	alloc = (old_state == GFS2_BLKST_FREE) ? 0x55 : 0;
 
 	while (byte < end) {
+		/* If we're looking for a free block we can eliminate all
+		   bitmap settings with 0x55, which represents four data
+		   blocks in a row.  If we're looking for a data block, we can
+		   eliminate 0x00 which corresponds to four free blocks. */
 		if ((*byte & 0x55) == alloc) {
 			blk += (8 - bit) >> 1;
 
@@ -859,23 +863,28 @@
 static struct inode *try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked)
 {
 	struct inode *inode;
-	u32 goal = 0;
+	u32 goal = 0, block;
 	u64 no_addr;
+	struct gfs2_sbd *sdp = rgd->rd_sbd;
 
 	for(;;) {
 		if (goal >= rgd->rd_data)
 			break;
-		goal = rgblk_search(rgd, goal, GFS2_BLKST_UNLINKED,
-				    GFS2_BLKST_UNLINKED);
-		if (goal == BFITNOENT)
+		down_write(&sdp->sd_log_flush_lock);
+		block = rgblk_search(rgd, goal, GFS2_BLKST_UNLINKED,
+				     GFS2_BLKST_UNLINKED);
+		up_write(&sdp->sd_log_flush_lock);
+		if (block == BFITNOENT)
 			break;
-		no_addr = goal + rgd->rd_data0;
+		/* rgblk_search can return a block < goal, so we need to
+		   keep it marching forward. */
+		no_addr = block + rgd->rd_data0;
 		goal++;
-		if (no_addr < *last_unlinked)
+		if (*last_unlinked != NO_BLOCK && no_addr <= *last_unlinked)
 			continue;
 		*last_unlinked = no_addr;
 		inode = gfs2_inode_lookup(rgd->rd_sbd->sd_vfs, DT_UNKNOWN,
-					  no_addr, -1);
+					  no_addr, -1, 1);
 		if (!IS_ERR(inode))
 			return inode;
 	}
@@ -1152,7 +1161,7 @@
 	struct gfs2_alloc *al = &ip->i_alloc;
 	struct inode *inode;
 	int error = 0;
-	u64 last_unlinked = 0;
+	u64 last_unlinked = NO_BLOCK;
 
 	if (gfs2_assert_warn(sdp, al->al_requested))
 		return -EINVAL;
@@ -1289,7 +1298,9 @@
 	   allocatable block anywhere else, we want to be able wrap around and
 	   search in the first part of our first-searched bit block.  */
 	for (x = 0; x <= length; x++) {
-		if (bi->bi_clone)
+		/* The GFS2_BLKST_UNLINKED state doesn't apply to the clone
+		   bitmaps, so we must search the originals for that. */
+		if (old_state != GFS2_BLKST_UNLINKED && bi->bi_clone)
 			blk = gfs2_bitfit(rgd, bi->bi_clone + bi->bi_offset,
 					  bi->bi_len, goal, old_state);
 		else
@@ -1305,9 +1316,7 @@
 		goal = 0;
 	}
 
-	if (old_state != new_state) {
-		gfs2_assert_withdraw(rgd->rd_sbd, blk != BFITNOENT);
-
+	if (blk != BFITNOENT && old_state != new_state) {
 		gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1);
 		gfs2_setbit(rgd, bi->bi_bh->b_data + bi->bi_offset,
 			    bi->bi_len, blk, new_state);
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index a2da76b..dd3e737 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -58,7 +58,6 @@
 	gt->gt_incore_log_blocks = 1024;
 	gt->gt_log_flush_secs = 60;
 	gt->gt_jindex_refresh_secs = 60;
-	gt->gt_scand_secs = 15;
 	gt->gt_recoverd_secs = 60;
 	gt->gt_logd_secs = 1;
 	gt->gt_quotad_secs = 5;
diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c
index c26c21b..06e0b77 100644
--- a/fs/gfs2/sys.c
+++ b/fs/gfs2/sys.c
@@ -222,7 +222,6 @@
 };
 
 static struct kset gfs2_kset = {
-	.kobj   = {.name = "gfs2"},
 	.ktype  = &gfs2_ktype,
 };
 
@@ -442,7 +441,6 @@
 TUNE_ATTR(quota_cache_secs, 1);
 TUNE_ATTR(stall_secs, 1);
 TUNE_ATTR(statfs_quantum, 1);
-TUNE_ATTR_DAEMON(scand_secs, scand_process);
 TUNE_ATTR_DAEMON(recoverd_secs, recoverd_process);
 TUNE_ATTR_DAEMON(logd_secs, logd_process);
 TUNE_ATTR_DAEMON(quotad_secs, quotad_process);
@@ -464,7 +462,6 @@
 	&tune_attr_quota_cache_secs.attr,
 	&tune_attr_stall_secs.attr,
 	&tune_attr_statfs_quantum.attr,
-	&tune_attr_scand_secs.attr,
 	&tune_attr_recoverd_secs.attr,
 	&tune_attr_logd_secs.attr,
 	&tune_attr_quotad_secs.attr,
@@ -553,6 +550,7 @@
 {
 	gfs2_sys_margs = NULL;
 	spin_lock_init(&gfs2_sys_margs_lock);
+	kobject_set_name(&gfs2_kset.kobj, "gfs2");
 	kobj_set_kset_s(&gfs2_kset, fs_subsys);
 	return kset_register(&gfs2_kset);
 }
diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c
index f8dabf8..717983e 100644
--- a/fs/gfs2/trans.c
+++ b/fs/gfs2/trans.c
@@ -142,25 +142,25 @@
 	lops_add(sdp, &bd->bd_le);
 }
 
-void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, u64 blkno)
+void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd)
 {
-	struct gfs2_revoke *rv = kmalloc(sizeof(struct gfs2_revoke),
-					 GFP_NOFS | __GFP_NOFAIL);
-	lops_init_le(&rv->rv_le, &gfs2_revoke_lops);
-	rv->rv_blkno = blkno;
-	lops_add(sdp, &rv->rv_le);
+	BUG_ON(!list_empty(&bd->bd_le.le_list));
+	BUG_ON(!list_empty(&bd->bd_ail_st_list));
+	BUG_ON(!list_empty(&bd->bd_ail_gl_list));
+	lops_init_le(&bd->bd_le, &gfs2_revoke_lops);
+	lops_add(sdp, &bd->bd_le);
 }
 
 void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno)
 {
-	struct gfs2_revoke *rv;
+	struct gfs2_bufdata *bd;
 	int found = 0;
 
 	gfs2_log_lock(sdp);
 
-	list_for_each_entry(rv, &sdp->sd_log_le_revoke, rv_le.le_list) {
-		if (rv->rv_blkno == blkno) {
-			list_del(&rv->rv_le.le_list);
+	list_for_each_entry(bd, &sdp->sd_log_le_revoke, bd_le.le_list) {
+		if (bd->bd_blkno == blkno) {
+			list_del_init(&bd->bd_le.le_list);
 			gfs2_assert_withdraw(sdp, sdp->sd_log_num_revoke);
 			sdp->sd_log_num_revoke--;
 			found = 1;
@@ -172,7 +172,7 @@
 
 	if (found) {
 		struct gfs2_trans *tr = current->journal_info;
-		kfree(rv);
+		kmem_cache_free(gfs2_bufdata_cachep, bd);
 		tr->tr_num_revoke_rm++;
 	}
 }
diff --git a/fs/gfs2/trans.h b/fs/gfs2/trans.h
index 23d4cbe..043d5f4 100644
--- a/fs/gfs2/trans.h
+++ b/fs/gfs2/trans.h
@@ -32,7 +32,7 @@
 
 void gfs2_trans_add_gl(struct gfs2_glock *gl);
 void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta);
-void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, u64 blkno);
+void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd);
 void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno);
 void gfs2_trans_add_rg(struct gfs2_rgrpd *rgd);
 
diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog
index af4ef80..345798e 100644
--- a/fs/ntfs/ChangeLog
+++ b/fs/ntfs/ChangeLog
@@ -17,6 +17,18 @@
 	  happen is unclear however so it is worth waiting until someone hits
 	  the problem.
 
+2.1.29 - Fix a deadlock at mount time.
+
+	- During mount the VFS holds s_umount lock on the superblock.  So when
+	  we try to empty the journal $LogFile contents by calling
+	  ntfs_attr_set() when the machine does not have much memory and the
+	  journal is large ntfs_attr_set() results in the VM trying to balance
+	  dirty pages which in turn tries to that the s_umount lock and thus we
+	  get a deadlock.  The solution is to not use ntfs_attr_set() and
+	  instead do the zeroing by hand at the block level rather than page
+	  cache level.
+	- Fix sparse warnings.
+
 2.1.28 - Fix a deadlock.
 
 	- Fix deadlock in fs/ntfs/inode.c::ntfs_put_inode().  Thanks to Sergey
diff --git a/fs/ntfs/Makefile b/fs/ntfs/Makefile
index 8255083..58b6be9 100644
--- a/fs/ntfs/Makefile
+++ b/fs/ntfs/Makefile
@@ -6,7 +6,7 @@
 	     index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \
 	     unistr.o upcase.o
 
-EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.28\"
+EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.29\"
 
 ifeq ($(CONFIG_NTFS_DEBUG),y)
 EXTRA_CFLAGS += -DDEBUG
diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c
index 6e5c253..cfdc790 100644
--- a/fs/ntfs/aops.c
+++ b/fs/ntfs/aops.c
@@ -2,7 +2,7 @@
  * aops.c - NTFS kernel address space operations and page cache handling.
  *	    Part of the Linux-NTFS project.
  *
- * Copyright (c) 2001-2006 Anton Altaparmakov
+ * Copyright (c) 2001-2007 Anton Altaparmakov
  * Copyright (c) 2002 Richard Russon
  *
  * This program/include file is free software; you can redistribute it and/or
@@ -396,7 +396,7 @@
 	loff_t i_size;
 	struct inode *vi;
 	ntfs_inode *ni, *base_ni;
-	u8 *kaddr;
+	u8 *addr;
 	ntfs_attr_search_ctx *ctx;
 	MFT_RECORD *mrec;
 	unsigned long flags;
@@ -491,15 +491,15 @@
 		/* Race with shrinking truncate. */
 		attr_len = i_size;
 	}
-	kaddr = kmap_atomic(page, KM_USER0);
+	addr = kmap_atomic(page, KM_USER0);
 	/* Copy the data to the page. */
-	memcpy(kaddr, (u8*)ctx->attr +
+	memcpy(addr, (u8*)ctx->attr +
 			le16_to_cpu(ctx->attr->data.resident.value_offset),
 			attr_len);
 	/* Zero the remainder of the page. */
-	memset(kaddr + attr_len, 0, PAGE_CACHE_SIZE - attr_len);
+	memset(addr + attr_len, 0, PAGE_CACHE_SIZE - attr_len);
 	flush_dcache_page(page);
-	kunmap_atomic(kaddr, KM_USER0);
+	kunmap_atomic(addr, KM_USER0);
 put_unm_err_out:
 	ntfs_attr_put_search_ctx(ctx);
 unm_err_out:
@@ -1344,7 +1344,7 @@
 	loff_t i_size;
 	struct inode *vi = page->mapping->host;
 	ntfs_inode *base_ni = NULL, *ni = NTFS_I(vi);
-	char *kaddr;
+	char *addr;
 	ntfs_attr_search_ctx *ctx = NULL;
 	MFT_RECORD *m = NULL;
 	u32 attr_len;
@@ -1484,14 +1484,14 @@
 		/* Shrinking cannot fail. */
 		BUG_ON(err);
 	}
-	kaddr = kmap_atomic(page, KM_USER0);
+	addr = kmap_atomic(page, KM_USER0);
 	/* Copy the data from the page to the mft record. */
 	memcpy((u8*)ctx->attr +
 			le16_to_cpu(ctx->attr->data.resident.value_offset),
-			kaddr, attr_len);
+			addr, attr_len);
 	/* Zero out of bounds area in the page cache page. */
-	memset(kaddr + attr_len, 0, PAGE_CACHE_SIZE - attr_len);
-	kunmap_atomic(kaddr, KM_USER0);
+	memset(addr + attr_len, 0, PAGE_CACHE_SIZE - attr_len);
+	kunmap_atomic(addr, KM_USER0);
 	flush_dcache_page(page);
 	flush_dcache_mft_record_page(ctx->ntfs_ino);
 	/* We are done with the page. */
diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c
index 1c08fef..92dabdc 100644
--- a/fs/ntfs/attrib.c
+++ b/fs/ntfs/attrib.c
@@ -1,7 +1,7 @@
 /**
  * attrib.c - NTFS attribute operations.  Part of the Linux-NTFS project.
  *
- * Copyright (c) 2001-2006 Anton Altaparmakov
+ * Copyright (c) 2001-2007 Anton Altaparmakov
  * Copyright (c) 2002 Richard Russon
  *
  * This program/include file is free software; you can redistribute it and/or
@@ -2500,7 +2500,7 @@
 	struct page *page;
 	u8 *kaddr;
 	pgoff_t idx, end;
-	unsigned int start_ofs, end_ofs, size;
+	unsigned start_ofs, end_ofs, size;
 
 	ntfs_debug("Entering for ofs 0x%llx, cnt 0x%llx, val 0x%hx.",
 			(long long)ofs, (long long)cnt, val);
@@ -2548,6 +2548,8 @@
 		kunmap_atomic(kaddr, KM_USER0);
 		set_page_dirty(page);
 		page_cache_release(page);
+		balance_dirty_pages_ratelimited(mapping);
+		cond_resched();
 		if (idx == end)
 			goto done;
 		idx++;
@@ -2604,6 +2606,8 @@
 		kunmap_atomic(kaddr, KM_USER0);
 		set_page_dirty(page);
 		page_cache_release(page);
+		balance_dirty_pages_ratelimited(mapping);
+		cond_resched();
 	}
 done:
 	ntfs_debug("Done.");
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c
index ffcc504..c814204 100644
--- a/fs/ntfs/file.c
+++ b/fs/ntfs/file.c
@@ -1,7 +1,7 @@
 /*
  * file.c - NTFS kernel file operations.  Part of the Linux-NTFS project.
  *
- * Copyright (c) 2001-2006 Anton Altaparmakov
+ * Copyright (c) 2001-2007 Anton Altaparmakov
  *
  * This program/include file is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as published
@@ -26,7 +26,6 @@
 #include <linux/swap.h>
 #include <linux/uio.h>
 #include <linux/writeback.h>
-#include <linux/sched.h>
 
 #include <asm/page.h>
 #include <asm/uaccess.h>
@@ -362,7 +361,7 @@
 	volatile char c;
 
 	/* Set @end to the first byte outside the last page we care about. */
-	end = (const char __user*)PAGE_ALIGN((ptrdiff_t __user)uaddr + bytes);
+	end = (const char __user*)PAGE_ALIGN((unsigned long)uaddr + bytes);
 
 	while (!__get_user(c, uaddr) && (uaddr += PAGE_SIZE, uaddr < end))
 		;
@@ -532,7 +531,8 @@
 	blocksize_bits = vol->sb->s_blocksize_bits;
 	u = 0;
 	do {
-		struct page *page = pages[u];
+		page = pages[u];
+		BUG_ON(!page);
 		/*
 		 * create_empty_buffers() will create uptodate/dirty buffers if
 		 * the page is uptodate/dirty.
@@ -1291,7 +1291,7 @@
 		size_t bytes)
 {
 	struct page **last_page = pages + nr_pages;
-	char *kaddr;
+	char *addr;
 	size_t total = 0;
 	unsigned len;
 	int left;
@@ -1300,13 +1300,13 @@
 		len = PAGE_CACHE_SIZE - ofs;
 		if (len > bytes)
 			len = bytes;
-		kaddr = kmap_atomic(*pages, KM_USER0);
-		left = __copy_from_user_inatomic(kaddr + ofs, buf, len);
-		kunmap_atomic(kaddr, KM_USER0);
+		addr = kmap_atomic(*pages, KM_USER0);
+		left = __copy_from_user_inatomic(addr + ofs, buf, len);
+		kunmap_atomic(addr, KM_USER0);
 		if (unlikely(left)) {
 			/* Do it the slow way. */
-			kaddr = kmap(*pages);
-			left = __copy_from_user(kaddr + ofs, buf, len);
+			addr = kmap(*pages);
+			left = __copy_from_user(addr + ofs, buf, len);
 			kunmap(*pages);
 			if (unlikely(left))
 				goto err_out;
@@ -1408,26 +1408,26 @@
 		size_t *iov_ofs, size_t bytes)
 {
 	struct page **last_page = pages + nr_pages;
-	char *kaddr;
+	char *addr;
 	size_t copied, len, total = 0;
 
 	do {
 		len = PAGE_CACHE_SIZE - ofs;
 		if (len > bytes)
 			len = bytes;
-		kaddr = kmap_atomic(*pages, KM_USER0);
-		copied = __ntfs_copy_from_user_iovec_inatomic(kaddr + ofs,
+		addr = kmap_atomic(*pages, KM_USER0);
+		copied = __ntfs_copy_from_user_iovec_inatomic(addr + ofs,
 				*iov, *iov_ofs, len);
-		kunmap_atomic(kaddr, KM_USER0);
+		kunmap_atomic(addr, KM_USER0);
 		if (unlikely(copied != len)) {
 			/* Do it the slow way. */
-			kaddr = kmap(*pages);
-			copied = __ntfs_copy_from_user_iovec_inatomic(kaddr + ofs,
+			addr = kmap(*pages);
+			copied = __ntfs_copy_from_user_iovec_inatomic(addr + ofs,
 					*iov, *iov_ofs, len);
 			/*
 			 * Zero the rest of the target like __copy_from_user().
 			 */
-			memset(kaddr + ofs + copied, 0, len - copied);
+			memset(addr + ofs + copied, 0, len - copied);
 			kunmap(*pages);
 			if (unlikely(copied != len))
 				goto err_out;
@@ -1735,8 +1735,6 @@
 	read_unlock_irqrestore(&ni->size_lock, flags);
 	BUG_ON(initialized_size != i_size);
 	if (end > initialized_size) {
-		unsigned long flags;
-
 		write_lock_irqsave(&ni->size_lock, flags);
 		ni->initialized_size = end;
 		i_size_write(vi, end);
diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
index b532a73..e9da092 100644
--- a/fs/ntfs/inode.c
+++ b/fs/ntfs/inode.c
@@ -34,7 +34,6 @@
 #include "dir.h"
 #include "debug.h"
 #include "inode.h"
-#include "attrib.h"
 #include "lcnalloc.h"
 #include "malloc.h"
 #include "mft.h"
@@ -2500,8 +2499,6 @@
 	/* Resize the attribute record to best fit the new attribute size. */
 	if (new_size < vol->mft_record_size &&
 			!ntfs_resident_attr_value_resize(m, a, new_size)) {
-		unsigned long flags;
-
 		/* The resize succeeded! */
 		flush_dcache_mft_record_page(ctx->ntfs_ino);
 		mark_mft_record_dirty(ctx->ntfs_ino);
diff --git a/fs/ntfs/logfile.c b/fs/ntfs/logfile.c
index acfed32..d7932e9 100644
--- a/fs/ntfs/logfile.c
+++ b/fs/ntfs/logfile.c
@@ -1,7 +1,7 @@
 /*
  * logfile.c - NTFS kernel journal handling. Part of the Linux-NTFS project.
  *
- * Copyright (c) 2002-2005 Anton Altaparmakov
+ * Copyright (c) 2002-2007 Anton Altaparmakov
  *
  * This program/include file is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as published
@@ -724,24 +724,139 @@
  */
 bool ntfs_empty_logfile(struct inode *log_vi)
 {
-	ntfs_volume *vol = NTFS_SB(log_vi->i_sb);
+	VCN vcn, end_vcn;
+	ntfs_inode *log_ni = NTFS_I(log_vi);
+	ntfs_volume *vol = log_ni->vol;
+	struct super_block *sb = vol->sb;
+	runlist_element *rl;
+	unsigned long flags;
+	unsigned block_size, block_size_bits;
+	int err;
+	bool should_wait = true;
 
 	ntfs_debug("Entering.");
-	if (!NVolLogFileEmpty(vol)) {
-		int err;
-		
-		err = ntfs_attr_set(NTFS_I(log_vi), 0, i_size_read(log_vi),
-				0xff);
-		if (unlikely(err)) {
-			ntfs_error(vol->sb, "Failed to fill $LogFile with "
-					"0xff bytes (error code %i).", err);
-			return false;
-		}
-		/* Set the flag so we do not have to do it again on remount. */
-		NVolSetLogFileEmpty(vol);
+	if (NVolLogFileEmpty(vol)) {
+		ntfs_debug("Done.");
+		return true;
 	}
+	/*
+	 * We cannot use ntfs_attr_set() because we may be still in the middle
+	 * of a mount operation.  Thus we do the emptying by hand by first
+	 * zapping the page cache pages for the $LogFile/$DATA attribute and
+	 * then emptying each of the buffers in each of the clusters specified
+	 * by the runlist by hand.
+	 */
+	block_size = sb->s_blocksize;
+	block_size_bits = sb->s_blocksize_bits;
+	vcn = 0;
+	read_lock_irqsave(&log_ni->size_lock, flags);
+	end_vcn = (log_ni->initialized_size + vol->cluster_size_mask) >>
+			vol->cluster_size_bits;
+	read_unlock_irqrestore(&log_ni->size_lock, flags);
+	truncate_inode_pages(log_vi->i_mapping, 0);
+	down_write(&log_ni->runlist.lock);
+	rl = log_ni->runlist.rl;
+	if (unlikely(!rl || vcn < rl->vcn || !rl->length)) {
+map_vcn:
+		err = ntfs_map_runlist_nolock(log_ni, vcn, NULL);
+		if (err) {
+			ntfs_error(sb, "Failed to map runlist fragment (error "
+					"%d).", -err);
+			goto err;
+		}
+		rl = log_ni->runlist.rl;
+		BUG_ON(!rl || vcn < rl->vcn || !rl->length);
+	}
+	/* Seek to the runlist element containing @vcn. */
+	while (rl->length && vcn >= rl[1].vcn)
+		rl++;
+	do {
+		LCN lcn;
+		sector_t block, end_block;
+		s64 len;
+
+		/*
+		 * If this run is not mapped map it now and start again as the
+		 * runlist will have been updated.
+		 */
+		lcn = rl->lcn;
+		if (unlikely(lcn == LCN_RL_NOT_MAPPED)) {
+			vcn = rl->vcn;
+			goto map_vcn;
+		}
+		/* If this run is not valid abort with an error. */
+		if (unlikely(!rl->length || lcn < LCN_HOLE))
+			goto rl_err;
+		/* Skip holes. */
+		if (lcn == LCN_HOLE)
+			continue;
+		block = lcn << vol->cluster_size_bits >> block_size_bits;
+		len = rl->length;
+		if (rl[1].vcn > end_vcn)
+			len = end_vcn - rl->vcn;
+		end_block = (lcn + len) << vol->cluster_size_bits >>
+				block_size_bits;
+		/* Iterate over the blocks in the run and empty them. */
+		do {
+			struct buffer_head *bh;
+
+			/* Obtain the buffer, possibly not uptodate. */
+			bh = sb_getblk(sb, block);
+			BUG_ON(!bh);
+			/* Setup buffer i/o submission. */
+			lock_buffer(bh);
+			bh->b_end_io = end_buffer_write_sync;
+			get_bh(bh);
+			/* Set the entire contents of the buffer to 0xff. */
+			memset(bh->b_data, -1, block_size);
+			if (!buffer_uptodate(bh))
+				set_buffer_uptodate(bh);
+			if (buffer_dirty(bh))
+				clear_buffer_dirty(bh);
+			/*
+			 * Submit the buffer and wait for i/o to complete but
+			 * only for the first buffer so we do not miss really
+			 * serious i/o errors.  Once the first buffer has
+			 * completed ignore errors afterwards as we can assume
+			 * that if one buffer worked all of them will work.
+			 */
+			submit_bh(WRITE, bh);
+			if (should_wait) {
+				should_wait = false;
+				wait_on_buffer(bh);
+				if (unlikely(!buffer_uptodate(bh)))
+					goto io_err;
+			}
+			brelse(bh);
+		} while (++block < end_block);
+	} while ((++rl)->vcn < end_vcn);
+	up_write(&log_ni->runlist.lock);
+	/*
+	 * Zap the pages again just in case any got instantiated whilst we were
+	 * emptying the blocks by hand.  FIXME: We may not have completed
+	 * writing to all the buffer heads yet so this may happen too early.
+	 * We really should use a kernel thread to do the emptying
+	 * asynchronously and then we can also set the volume dirty and output
+	 * an error message if emptying should fail.
+	 */
+	truncate_inode_pages(log_vi->i_mapping, 0);
+	/* Set the flag so we do not have to do it again on remount. */
+	NVolSetLogFileEmpty(vol);
 	ntfs_debug("Done.");
 	return true;
+io_err:
+	ntfs_error(sb, "Failed to write buffer.  Unmount and run chkdsk.");
+	goto dirty_err;
+rl_err:
+	ntfs_error(sb, "Runlist is corrupt.  Unmount and run chkdsk.");
+dirty_err:
+	NVolSetErrors(vol);
+	err = -EIO;
+err:
+	up_write(&log_ni->runlist.lock);
+	ntfs_error(sb, "Failed to fill $LogFile with 0xff bytes (error %d).",
+			-err);
+	return false;
 }
 
 #endif /* NTFS_RW */
diff --git a/fs/ntfs/runlist.c b/fs/ntfs/runlist.c
index 9afd72c..56a9a6d2 100644
--- a/fs/ntfs/runlist.c
+++ b/fs/ntfs/runlist.c
@@ -1,7 +1,7 @@
 /**
  * runlist.c - NTFS runlist handling code.  Part of the Linux-NTFS project.
  *
- * Copyright (c) 2001-2005 Anton Altaparmakov
+ * Copyright (c) 2001-2007 Anton Altaparmakov
  * Copyright (c) 2002-2005 Richard Russon
  *
  * This program/include file is free software; you can redistribute it and/or
@@ -1714,7 +1714,7 @@
 					sizeof(*rl));
 		/* Adjust the beginning of the tail if necessary. */
 		if (end > rl->vcn) {
-			s64 delta = end - rl->vcn;
+			delta = end - rl->vcn;
 			rl->vcn = end;
 			rl->length -= delta;
 			/* Only adjust the lcn if it is real. */
diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c
index 778a850..4ba7f0b 100644
--- a/fs/ocfs2/alloc.c
+++ b/fs/ocfs2/alloc.c
@@ -354,7 +354,6 @@
 	enum ocfs2_append_type	ins_appending;
 	enum ocfs2_contig_type	ins_contig;
 	int			ins_contig_index;
-	int			ins_free_records;
 	int			ins_tree_depth;
 };
 
@@ -362,7 +361,6 @@
 	enum ocfs2_contig_type	c_contig_type;
 	int			c_has_empty_extent;
 	int			c_split_covers_rec;
-	int			c_used_tail_recs;
 };
 
 /*
@@ -2808,36 +2806,28 @@
 				     struct ocfs2_merge_ctxt *ctxt)
 
 {
-	int ret = 0, delete_tail_recs = 0;
+	int ret = 0;
 	struct ocfs2_extent_list *el = path_leaf_el(left_path);
 	struct ocfs2_extent_rec *rec = &el->l_recs[split_index];
 
 	BUG_ON(ctxt->c_contig_type == CONTIG_NONE);
 
-	if (ctxt->c_split_covers_rec) {
-		delete_tail_recs++;
-
-		if (ctxt->c_contig_type == CONTIG_LEFTRIGHT ||
-		    ctxt->c_has_empty_extent)
-			delete_tail_recs++;
-
-		if (ctxt->c_has_empty_extent) {
-			/*
-			 * The merge code will need to create an empty
-			 * extent to take the place of the newly
-			 * emptied slot. Remove any pre-existing empty
-			 * extents - having more than one in a leaf is
-			 * illegal.
-			 */
-			ret = ocfs2_rotate_tree_left(inode, handle, left_path,
-						     dealloc);
-			if (ret) {
-				mlog_errno(ret);
-				goto out;
-			}
-			split_index--;
-			rec = &el->l_recs[split_index];
+	if (ctxt->c_split_covers_rec && ctxt->c_has_empty_extent) {
+		/*
+		 * The merge code will need to create an empty
+		 * extent to take the place of the newly
+		 * emptied slot. Remove any pre-existing empty
+		 * extents - having more than one in a leaf is
+		 * illegal.
+		 */
+		ret = ocfs2_rotate_tree_left(inode, handle, left_path,
+					     dealloc);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
 		}
+		split_index--;
+		rec = &el->l_recs[split_index];
 	}
 
 	if (ctxt->c_contig_type == CONTIG_LEFTRIGHT) {
@@ -3593,6 +3583,7 @@
 				    struct buffer_head *di_bh,
 				    struct buffer_head **last_eb_bh,
 				    struct ocfs2_extent_rec *insert_rec,
+				    int *free_records,
 				    struct ocfs2_insert_type *insert)
 {
 	int ret;
@@ -3633,7 +3624,7 @@
 	 * XXX: This test is simplistic, we can search for empty
 	 * extent records too.
 	 */
-	insert->ins_free_records = le16_to_cpu(el->l_count) -
+	*free_records = le16_to_cpu(el->l_count) -
 		le16_to_cpu(el->l_next_free_rec);
 
 	if (!insert->ins_tree_depth) {
@@ -3730,10 +3721,13 @@
 			struct ocfs2_alloc_context *meta_ac)
 {
 	int status;
+	int uninitialized_var(free_records);
 	struct buffer_head *last_eb_bh = NULL;
 	struct ocfs2_insert_type insert = {0, };
 	struct ocfs2_extent_rec rec;
 
+	BUG_ON(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL);
+
 	mlog(0, "add %u clusters at position %u to inode %llu\n",
 	     new_clusters, cpos, (unsigned long long)OCFS2_I(inode)->ip_blkno);
 
@@ -3752,7 +3746,7 @@
 	rec.e_flags = flags;
 
 	status = ocfs2_figure_insert_type(inode, fe_bh, &last_eb_bh, &rec,
-					  &insert);
+					  &free_records, &insert);
 	if (status < 0) {
 		mlog_errno(status);
 		goto bail;
@@ -3762,9 +3756,9 @@
 	     "Insert.contig_index: %d, Insert.free_records: %d, "
 	     "Insert.tree_depth: %d\n",
 	     insert.ins_appending, insert.ins_contig, insert.ins_contig_index,
-	     insert.ins_free_records, insert.ins_tree_depth);
+	     free_records, insert.ins_tree_depth);
 
-	if (insert.ins_contig == CONTIG_NONE && insert.ins_free_records == 0) {
+	if (insert.ins_contig == CONTIG_NONE && free_records == 0) {
 		status = ocfs2_grow_tree(inode, handle, fe_bh,
 					 &insert.ins_tree_depth, &last_eb_bh,
 					 meta_ac);
@@ -3847,26 +3841,17 @@
 
 	if (le16_to_cpu(rightmost_el->l_next_free_rec) ==
 	    le16_to_cpu(rightmost_el->l_count)) {
-		int old_depth = depth;
-
 		ret = ocfs2_grow_tree(inode, handle, di_bh, &depth, last_eb_bh,
 				      meta_ac);
 		if (ret) {
 			mlog_errno(ret);
 			goto out;
 		}
-
-		if (old_depth != depth) {
-			eb = (struct ocfs2_extent_block *)(*last_eb_bh)->b_data;
-			rightmost_el = &eb->h_list;
-		}
 	}
 
 	memset(&insert, 0, sizeof(struct ocfs2_insert_type));
 	insert.ins_appending = APPEND_NONE;
 	insert.ins_contig = CONTIG_NONE;
-	insert.ins_free_records = le16_to_cpu(rightmost_el->l_count)
-		- le16_to_cpu(rightmost_el->l_next_free_rec);
 	insert.ins_tree_depth = depth;
 
 	insert_range = le32_to_cpu(split_rec.e_cpos) +
@@ -4015,11 +4000,6 @@
 	} else
 		rightmost_el = path_root_el(path);
 
-	ctxt.c_used_tail_recs = le16_to_cpu(rightmost_el->l_next_free_rec);
-	if (ctxt.c_used_tail_recs > 0 &&
-	    ocfs2_is_empty_extent(&rightmost_el->l_recs[0]))
-		ctxt.c_used_tail_recs--;
-
 	if (rec->e_cpos == split_rec->e_cpos &&
 	    rec->e_leaf_clusters == split_rec->e_leaf_clusters)
 		ctxt.c_split_covers_rec = 1;
@@ -4028,10 +4008,9 @@
 
 	ctxt.c_has_empty_extent = ocfs2_is_empty_extent(&el->l_recs[0]);
 
-	mlog(0, "index: %d, contig: %u, used_tail_recs: %u, "
-	     "has_empty: %u, split_covers: %u\n", split_index,
-	     ctxt.c_contig_type, ctxt.c_used_tail_recs,
-	     ctxt.c_has_empty_extent, ctxt.c_split_covers_rec);
+	mlog(0, "index: %d, contig: %u, has_empty: %u, split_covers: %u\n",
+	     split_index, ctxt.c_contig_type, ctxt.c_has_empty_extent,
+	     ctxt.c_split_covers_rec);
 
 	if (ctxt.c_contig_type == CONTIG_NONE) {
 		if (ctxt.c_split_covers_rec)
@@ -4180,27 +4159,18 @@
 
 	if (le16_to_cpu(rightmost_el->l_next_free_rec) ==
 	    le16_to_cpu(rightmost_el->l_count)) {
-		int old_depth = depth;
-
 		ret = ocfs2_grow_tree(inode, handle, di_bh, &depth, &last_eb_bh,
 				      meta_ac);
 		if (ret) {
 			mlog_errno(ret);
 			goto out;
 		}
-
-		if (old_depth != depth) {
-			eb = (struct ocfs2_extent_block *)last_eb_bh->b_data;
-			rightmost_el = &eb->h_list;
-		}
 	}
 
 	memset(&insert, 0, sizeof(struct ocfs2_insert_type));
 	insert.ins_appending = APPEND_NONE;
 	insert.ins_contig = CONTIG_NONE;
 	insert.ins_split = SPLIT_RIGHT;
-	insert.ins_free_records = le16_to_cpu(rightmost_el->l_count)
-		- le16_to_cpu(rightmost_el->l_next_free_rec);
 	insert.ins_tree_depth = depth;
 
 	ret = ocfs2_do_insert_extent(inode, handle, di_bh, &split_rec, &insert);
@@ -5665,12 +5635,50 @@
 	return ocfs2_journal_dirty_data(handle, bh);
 }
 
+static void ocfs2_map_and_dirty_page(struct inode *inode, handle_t *handle,
+				     unsigned int from, unsigned int to,
+				     struct page *page, int zero, u64 *phys)
+{
+	int ret, partial = 0;
+
+	ret = ocfs2_map_page_blocks(page, phys, inode, from, to, 0);
+	if (ret)
+		mlog_errno(ret);
+
+	if (zero)
+		zero_user_page(page, from, to - from, KM_USER0);
+
+	/*
+	 * Need to set the buffers we zero'd into uptodate
+	 * here if they aren't - ocfs2_map_page_blocks()
+	 * might've skipped some
+	 */
+	if (ocfs2_should_order_data(inode)) {
+		ret = walk_page_buffers(handle,
+					page_buffers(page),
+					from, to, &partial,
+					ocfs2_ordered_zero_func);
+		if (ret < 0)
+			mlog_errno(ret);
+	} else {
+		ret = walk_page_buffers(handle, page_buffers(page),
+					from, to, &partial,
+					ocfs2_writeback_zero_func);
+		if (ret < 0)
+			mlog_errno(ret);
+	}
+
+	if (!partial)
+		SetPageUptodate(page);
+
+	flush_dcache_page(page);
+}
+
 static void ocfs2_zero_cluster_pages(struct inode *inode, loff_t start,
 				     loff_t end, struct page **pages,
 				     int numpages, u64 phys, handle_t *handle)
 {
-	int i, ret, partial = 0;
-	void *kaddr;
+	int i;
 	struct page *page;
 	unsigned int from, to = PAGE_CACHE_SIZE;
 	struct super_block *sb = inode->i_sb;
@@ -5691,87 +5699,31 @@
 		BUG_ON(from > PAGE_CACHE_SIZE);
 		BUG_ON(to > PAGE_CACHE_SIZE);
 
-		ret = ocfs2_map_page_blocks(page, &phys, inode, from, to, 0);
-		if (ret)
-			mlog_errno(ret);
-
-		kaddr = kmap_atomic(page, KM_USER0);
-		memset(kaddr + from, 0, to - from);
-		kunmap_atomic(kaddr, KM_USER0);
-
-		/*
-		 * Need to set the buffers we zero'd into uptodate
-		 * here if they aren't - ocfs2_map_page_blocks()
-		 * might've skipped some
-		 */
-		if (ocfs2_should_order_data(inode)) {
-			ret = walk_page_buffers(handle,
-						page_buffers(page),
-						from, to, &partial,
-						ocfs2_ordered_zero_func);
-			if (ret < 0)
-				mlog_errno(ret);
-		} else {
-			ret = walk_page_buffers(handle, page_buffers(page),
-						from, to, &partial,
-						ocfs2_writeback_zero_func);
-			if (ret < 0)
-				mlog_errno(ret);
-		}
-
-		if (!partial)
-			SetPageUptodate(page);
-
-		flush_dcache_page(page);
+		ocfs2_map_and_dirty_page(inode, handle, from, to, page, 1,
+					 &phys);
 
 		start = (page->index + 1) << PAGE_CACHE_SHIFT;
 	}
 out:
-	if (pages) {
-		for (i = 0; i < numpages; i++) {
-			page = pages[i];
-			unlock_page(page);
-			mark_page_accessed(page);
-			page_cache_release(page);
-		}
-	}
+	if (pages)
+		ocfs2_unlock_and_free_pages(pages, numpages);
 }
 
 static int ocfs2_grab_eof_pages(struct inode *inode, loff_t start, loff_t end,
-				struct page **pages, int *num, u64 *phys)
+				struct page **pages, int *num)
 {
-	int i, numpages = 0, ret = 0;
-	unsigned int ext_flags;
+	int numpages, ret = 0;
 	struct super_block *sb = inode->i_sb;
 	struct address_space *mapping = inode->i_mapping;
 	unsigned long index;
 	loff_t last_page_bytes;
 
-	BUG_ON(!ocfs2_sparse_alloc(OCFS2_SB(sb)));
 	BUG_ON(start > end);
 
-	if (start == end)
-		goto out;
-
 	BUG_ON(start >> OCFS2_SB(sb)->s_clustersize_bits !=
 	       (end - 1) >> OCFS2_SB(sb)->s_clustersize_bits);
 
-	ret = ocfs2_extent_map_get_blocks(inode, start >> sb->s_blocksize_bits,
-					  phys, NULL, &ext_flags);
-	if (ret) {
-		mlog_errno(ret);
-		goto out;
-	}
-
-	/* Tail is a hole. */
-	if (*phys == 0)
-		goto out;
-
-	/* Tail is marked as unwritten, we can count on write to zero
-	 * in that case. */
-	if (ext_flags & OCFS2_EXT_UNWRITTEN)
-		goto out;
-
+	numpages = 0;
 	last_page_bytes = PAGE_ALIGN(end);
 	index = start >> PAGE_CACHE_SHIFT;
 	do {
@@ -5788,14 +5740,8 @@
 
 out:
 	if (ret != 0) {
-		if (pages) {
-			for (i = 0; i < numpages; i++) {
-				if (pages[i]) {
-					unlock_page(pages[i]);
-					page_cache_release(pages[i]);
-				}
-			}
-		}
+		if (pages)
+			ocfs2_unlock_and_free_pages(pages, numpages);
 		numpages = 0;
 	}
 
@@ -5816,18 +5762,20 @@
 int ocfs2_zero_range_for_truncate(struct inode *inode, handle_t *handle,
 				  u64 range_start, u64 range_end)
 {
-	int ret, numpages;
+	int ret = 0, numpages;
 	struct page **pages = NULL;
 	u64 phys;
+	unsigned int ext_flags;
+	struct super_block *sb = inode->i_sb;
 
 	/*
 	 * File systems which don't support sparse files zero on every
 	 * extend.
 	 */
-	if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)))
+	if (!ocfs2_sparse_alloc(OCFS2_SB(sb)))
 		return 0;
 
-	pages = kcalloc(ocfs2_pages_per_cluster(inode->i_sb),
+	pages = kcalloc(ocfs2_pages_per_cluster(sb),
 			sizeof(struct page *), GFP_NOFS);
 	if (pages == NULL) {
 		ret = -ENOMEM;
@@ -5835,16 +5783,31 @@
 		goto out;
 	}
 
-	ret = ocfs2_grab_eof_pages(inode, range_start, range_end, pages,
-				   &numpages, &phys);
+	if (range_start == range_end)
+		goto out;
+
+	ret = ocfs2_extent_map_get_blocks(inode,
+					  range_start >> sb->s_blocksize_bits,
+					  &phys, NULL, &ext_flags);
 	if (ret) {
 		mlog_errno(ret);
 		goto out;
 	}
 
-	if (numpages == 0)
+	/*
+	 * Tail is a hole, or is marked unwritten. In either case, we
+	 * can count on read and write to return/push zero's.
+	 */
+	if (phys == 0 || ext_flags & OCFS2_EXT_UNWRITTEN)
 		goto out;
 
+	ret = ocfs2_grab_eof_pages(inode, range_start, range_end, pages,
+				   &numpages);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
 	ocfs2_zero_cluster_pages(inode, range_start, range_end, pages,
 				 numpages, phys, handle);
 
@@ -5865,6 +5828,178 @@
 	return ret;
 }
 
+static void ocfs2_zero_dinode_id2(struct inode *inode, struct ocfs2_dinode *di)
+{
+	unsigned int blocksize = 1 << inode->i_sb->s_blocksize_bits;
+
+	memset(&di->id2, 0, blocksize - offsetof(struct ocfs2_dinode, id2));
+}
+
+void ocfs2_dinode_new_extent_list(struct inode *inode,
+				  struct ocfs2_dinode *di)
+{
+	ocfs2_zero_dinode_id2(inode, di);
+	di->id2.i_list.l_tree_depth = 0;
+	di->id2.i_list.l_next_free_rec = 0;
+	di->id2.i_list.l_count = cpu_to_le16(ocfs2_extent_recs_per_inode(inode->i_sb));
+}
+
+void ocfs2_set_inode_data_inline(struct inode *inode, struct ocfs2_dinode *di)
+{
+	struct ocfs2_inode_info *oi = OCFS2_I(inode);
+	struct ocfs2_inline_data *idata = &di->id2.i_data;
+
+	spin_lock(&oi->ip_lock);
+	oi->ip_dyn_features |= OCFS2_INLINE_DATA_FL;
+	di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features);
+	spin_unlock(&oi->ip_lock);
+
+	/*
+	 * We clear the entire i_data structure here so that all
+	 * fields can be properly initialized.
+	 */
+	ocfs2_zero_dinode_id2(inode, di);
+
+	idata->id_count = cpu_to_le16(ocfs2_max_inline_data(inode->i_sb));
+}
+
+int ocfs2_convert_inline_data_to_extents(struct inode *inode,
+					 struct buffer_head *di_bh)
+{
+	int ret, i, has_data, num_pages = 0;
+	handle_t *handle;
+	u64 uninitialized_var(block);
+	struct ocfs2_inode_info *oi = OCFS2_I(inode);
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+	struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+	struct ocfs2_alloc_context *data_ac = NULL;
+	struct page **pages = NULL;
+	loff_t end = osb->s_clustersize;
+
+	has_data = i_size_read(inode) ? 1 : 0;
+
+	if (has_data) {
+		pages = kcalloc(ocfs2_pages_per_cluster(osb->sb),
+				sizeof(struct page *), GFP_NOFS);
+		if (pages == NULL) {
+			ret = -ENOMEM;
+			mlog_errno(ret);
+			goto out;
+		}
+
+		ret = ocfs2_reserve_clusters(osb, 1, &data_ac);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+	}
+
+	handle = ocfs2_start_trans(osb, OCFS2_INLINE_TO_EXTENTS_CREDITS);
+	if (IS_ERR(handle)) {
+		ret = PTR_ERR(handle);
+		mlog_errno(ret);
+		goto out_unlock;
+	}
+
+	ret = ocfs2_journal_access(handle, inode, di_bh,
+				   OCFS2_JOURNAL_ACCESS_WRITE);
+	if (ret) {
+		mlog_errno(ret);
+		goto out_commit;
+	}
+
+	if (has_data) {
+		u32 bit_off, num;
+		unsigned int page_end;
+		u64 phys;
+
+		ret = ocfs2_claim_clusters(osb, handle, data_ac, 1, &bit_off,
+					   &num);
+		if (ret) {
+			mlog_errno(ret);
+			goto out_commit;
+		}
+
+		/*
+		 * Save two copies, one for insert, and one that can
+		 * be changed by ocfs2_map_and_dirty_page() below.
+		 */
+		block = phys = ocfs2_clusters_to_blocks(inode->i_sb, bit_off);
+
+		/*
+		 * Non sparse file systems zero on extend, so no need
+		 * to do that now.
+		 */
+		if (!ocfs2_sparse_alloc(osb) &&
+		    PAGE_CACHE_SIZE < osb->s_clustersize)
+			end = PAGE_CACHE_SIZE;
+
+		ret = ocfs2_grab_eof_pages(inode, 0, end, pages, &num_pages);
+		if (ret) {
+			mlog_errno(ret);
+			goto out_commit;
+		}
+
+		/*
+		 * This should populate the 1st page for us and mark
+		 * it up to date.
+		 */
+		ret = ocfs2_read_inline_data(inode, pages[0], di_bh);
+		if (ret) {
+			mlog_errno(ret);
+			goto out_commit;
+		}
+
+		page_end = PAGE_CACHE_SIZE;
+		if (PAGE_CACHE_SIZE > osb->s_clustersize)
+			page_end = osb->s_clustersize;
+
+		for (i = 0; i < num_pages; i++)
+			ocfs2_map_and_dirty_page(inode, handle, 0, page_end,
+						 pages[i], i > 0, &phys);
+	}
+
+	spin_lock(&oi->ip_lock);
+	oi->ip_dyn_features &= ~OCFS2_INLINE_DATA_FL;
+	di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features);
+	spin_unlock(&oi->ip_lock);
+
+	ocfs2_dinode_new_extent_list(inode, di);
+
+	ocfs2_journal_dirty(handle, di_bh);
+
+	if (has_data) {
+		/*
+		 * An error at this point should be extremely rare. If
+		 * this proves to be false, we could always re-build
+		 * the in-inode data from our pages.
+		 */
+		ret = ocfs2_insert_extent(osb, handle, inode, di_bh,
+					  0, block, 1, 0, NULL);
+		if (ret) {
+			mlog_errno(ret);
+			goto out_commit;
+		}
+
+		inode->i_blocks = ocfs2_inode_sector_count(inode);
+	}
+
+out_commit:
+	ocfs2_commit_trans(osb, handle);
+
+out_unlock:
+	if (data_ac)
+		ocfs2_free_alloc_context(data_ac);
+
+out:
+	if (pages) {
+		ocfs2_unlock_and_free_pages(pages, num_pages);
+		kfree(pages);
+	}
+
+	return ret;
+}
+
 /*
  * It is expected, that by the time you call this function,
  * inode->i_size and fe->i_size have been adjusted.
@@ -6090,6 +6225,81 @@
 	return status;
 }
 
+/*
+ * 'start' is inclusive, 'end' is not.
+ */
+int ocfs2_truncate_inline(struct inode *inode, struct buffer_head *di_bh,
+			  unsigned int start, unsigned int end, int trunc)
+{
+	int ret;
+	unsigned int numbytes;
+	handle_t *handle;
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+	struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+	struct ocfs2_inline_data *idata = &di->id2.i_data;
+
+	if (end > i_size_read(inode))
+		end = i_size_read(inode);
+
+	BUG_ON(start >= end);
+
+	if (!(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) ||
+	    !(le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_DATA_FL) ||
+	    !ocfs2_supports_inline_data(osb)) {
+		ocfs2_error(inode->i_sb,
+			    "Inline data flags for inode %llu don't agree! "
+			    "Disk: 0x%x, Memory: 0x%x, Superblock: 0x%x\n",
+			    (unsigned long long)OCFS2_I(inode)->ip_blkno,
+			    le16_to_cpu(di->i_dyn_features),
+			    OCFS2_I(inode)->ip_dyn_features,
+			    osb->s_feature_incompat);
+		ret = -EROFS;
+		goto out;
+	}
+
+	handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
+	if (IS_ERR(handle)) {
+		ret = PTR_ERR(handle);
+		mlog_errno(ret);
+		goto out;
+	}
+
+	ret = ocfs2_journal_access(handle, inode, di_bh,
+				   OCFS2_JOURNAL_ACCESS_WRITE);
+	if (ret) {
+		mlog_errno(ret);
+		goto out_commit;
+	}
+
+	numbytes = end - start;
+	memset(idata->id_data + start, 0, numbytes);
+
+	/*
+	 * No need to worry about the data page here - it's been
+	 * truncated already and inline data doesn't need it for
+	 * pushing zero's to disk, so we'll let readpage pick it up
+	 * later.
+	 */
+	if (trunc) {
+		i_size_write(inode, start);
+		di->i_size = cpu_to_le64(start);
+	}
+
+	inode->i_blocks = ocfs2_inode_sector_count(inode);
+	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+
+	di->i_ctime = di->i_mtime = cpu_to_le64(inode->i_ctime.tv_sec);
+	di->i_ctime_nsec = di->i_mtime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
+
+	ocfs2_journal_dirty(handle, di_bh);
+
+out_commit:
+	ocfs2_commit_trans(osb, handle);
+
+out:
+	return ret;
+}
+
 static void ocfs2_free_truncate_context(struct ocfs2_truncate_context *tc)
 {
 	/*
diff --git a/fs/ocfs2/alloc.h b/fs/ocfs2/alloc.h
index 990df48..42ff94b 100644
--- a/fs/ocfs2/alloc.h
+++ b/fs/ocfs2/alloc.h
@@ -62,6 +62,11 @@
 	return le16_to_cpu(fe->id2.i_list.l_tree_depth) + 2;
 }
 
+void ocfs2_dinode_new_extent_list(struct inode *inode, struct ocfs2_dinode *di);
+void ocfs2_set_inode_data_inline(struct inode *inode, struct ocfs2_dinode *di);
+int ocfs2_convert_inline_data_to_extents(struct inode *inode,
+					 struct buffer_head *di_bh);
+
 int ocfs2_truncate_log_init(struct ocfs2_super *osb);
 void ocfs2_truncate_log_shutdown(struct ocfs2_super *osb);
 void ocfs2_schedule_truncate_log_flush(struct ocfs2_super *osb,
@@ -115,6 +120,8 @@
 			  struct inode *inode,
 			  struct buffer_head *fe_bh,
 			  struct ocfs2_truncate_context *tc);
+int ocfs2_truncate_inline(struct inode *inode, struct buffer_head *di_bh,
+			  unsigned int start, unsigned int end, int trunc);
 
 int ocfs2_find_leaf(struct inode *inode, struct ocfs2_extent_list *root_el,
 		    u32 cpos, struct buffer_head **leaf_bh);
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
index f37f25c..34d1045 100644
--- a/fs/ocfs2/aops.c
+++ b/fs/ocfs2/aops.c
@@ -206,9 +206,70 @@
 	return err;
 }
 
+int ocfs2_read_inline_data(struct inode *inode, struct page *page,
+			   struct buffer_head *di_bh)
+{
+	void *kaddr;
+	unsigned int size;
+	struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+
+	if (!(le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_DATA_FL)) {
+		ocfs2_error(inode->i_sb, "Inode %llu lost inline data flag",
+			    (unsigned long long)OCFS2_I(inode)->ip_blkno);
+		return -EROFS;
+	}
+
+	size = i_size_read(inode);
+
+	if (size > PAGE_CACHE_SIZE ||
+	    size > ocfs2_max_inline_data(inode->i_sb)) {
+		ocfs2_error(inode->i_sb,
+			    "Inode %llu has with inline data has bad size: %u",
+			    (unsigned long long)OCFS2_I(inode)->ip_blkno, size);
+		return -EROFS;
+	}
+
+	kaddr = kmap_atomic(page, KM_USER0);
+	if (size)
+		memcpy(kaddr, di->id2.i_data.id_data, size);
+	/* Clear the remaining part of the page */
+	memset(kaddr + size, 0, PAGE_CACHE_SIZE - size);
+	flush_dcache_page(page);
+	kunmap_atomic(kaddr, KM_USER0);
+
+	SetPageUptodate(page);
+
+	return 0;
+}
+
+static int ocfs2_readpage_inline(struct inode *inode, struct page *page)
+{
+	int ret;
+	struct buffer_head *di_bh = NULL;
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+	BUG_ON(!PageLocked(page));
+	BUG_ON(!OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL);
+
+	ret = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno, &di_bh,
+			       OCFS2_BH_CACHED, inode);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	ret = ocfs2_read_inline_data(inode, page, di_bh);
+out:
+	unlock_page(page);
+
+	brelse(di_bh);
+	return ret;
+}
+
 static int ocfs2_readpage(struct file *file, struct page *page)
 {
 	struct inode *inode = page->mapping->host;
+	struct ocfs2_inode_info *oi = OCFS2_I(inode);
 	loff_t start = (loff_t)page->index << PAGE_CACHE_SHIFT;
 	int ret, unlock = 1;
 
@@ -222,7 +283,7 @@
 		goto out;
 	}
 
-	if (down_read_trylock(&OCFS2_I(inode)->ip_alloc_sem) == 0) {
+	if (down_read_trylock(&oi->ip_alloc_sem) == 0) {
 		ret = AOP_TRUNCATED_PAGE;
 		goto out_meta_unlock;
 	}
@@ -252,7 +313,10 @@
 		goto out_alloc;
 	}
 
-	ret = block_read_full_page(page, ocfs2_get_block);
+	if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL)
+		ret = ocfs2_readpage_inline(inode, page);
+	else
+		ret = block_read_full_page(page, ocfs2_get_block);
 	unlock = 0;
 
 	ocfs2_data_unlock(inode, 0);
@@ -301,12 +365,8 @@
 {
 	int ret;
 
-	down_read(&OCFS2_I(inode)->ip_alloc_sem);
-
 	ret = block_prepare_write(page, from, to, ocfs2_get_block);
 
-	up_read(&OCFS2_I(inode)->ip_alloc_sem);
-
 	return ret;
 }
 
@@ -401,7 +461,9 @@
 		down_read(&OCFS2_I(inode)->ip_alloc_sem);
 	}
 
-	err = ocfs2_extent_map_get_blocks(inode, block, &p_blkno, NULL, NULL);
+	if (!(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL))
+		err = ocfs2_extent_map_get_blocks(inode, block, &p_blkno, NULL,
+						  NULL);
 
 	if (!INODE_JOURNAL(inode)) {
 		up_read(&OCFS2_I(inode)->ip_alloc_sem);
@@ -415,7 +477,6 @@
 		goto bail;
 	}
 
-
 bail:
 	status = err ? 0 : p_blkno;
 
@@ -570,6 +631,13 @@
 
 	mlog_entry_void();
 
+	/*
+	 * Fallback to buffered I/O if we see an inode without
+	 * extents.
+	 */
+	if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
+		return 0;
+
 	if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) {
 		/*
 		 * We get PR data locks even for O_DIRECT.  This
@@ -834,18 +902,22 @@
 	struct ocfs2_cached_dealloc_ctxt w_dealloc;
 };
 
-static void ocfs2_free_write_ctxt(struct ocfs2_write_ctxt *wc)
+void ocfs2_unlock_and_free_pages(struct page **pages, int num_pages)
 {
 	int i;
 
-	for(i = 0; i < wc->w_num_pages; i++) {
-		if (wc->w_pages[i] == NULL)
-			continue;
-
-		unlock_page(wc->w_pages[i]);
-		mark_page_accessed(wc->w_pages[i]);
-		page_cache_release(wc->w_pages[i]);
+	for(i = 0; i < num_pages; i++) {
+		if (pages[i]) {
+			unlock_page(pages[i]);
+			mark_page_accessed(pages[i]);
+			page_cache_release(pages[i]);
+		}
 	}
+}
+
+static void ocfs2_free_write_ctxt(struct ocfs2_write_ctxt *wc)
+{
+	ocfs2_unlock_and_free_pages(wc->w_pages, wc->w_num_pages);
 
 	brelse(wc->w_di_bh);
 	kfree(wc);
@@ -1360,6 +1432,160 @@
 	return ret;
 }
 
+static int ocfs2_write_begin_inline(struct address_space *mapping,
+				    struct inode *inode,
+				    struct ocfs2_write_ctxt *wc)
+{
+	int ret;
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+	struct page *page;
+	handle_t *handle;
+	struct ocfs2_dinode *di = (struct ocfs2_dinode *)wc->w_di_bh->b_data;
+
+	page = find_or_create_page(mapping, 0, GFP_NOFS);
+	if (!page) {
+		ret = -ENOMEM;
+		mlog_errno(ret);
+		goto out;
+	}
+	/*
+	 * If we don't set w_num_pages then this page won't get unlocked
+	 * and freed on cleanup of the write context.
+	 */
+	wc->w_pages[0] = wc->w_target_page = page;
+	wc->w_num_pages = 1;
+
+	handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
+	if (IS_ERR(handle)) {
+		ret = PTR_ERR(handle);
+		mlog_errno(ret);
+		goto out;
+	}
+
+	ret = ocfs2_journal_access(handle, inode, wc->w_di_bh,
+				   OCFS2_JOURNAL_ACCESS_WRITE);
+	if (ret) {
+		ocfs2_commit_trans(osb, handle);
+
+		mlog_errno(ret);
+		goto out;
+	}
+
+	if (!(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL))
+		ocfs2_set_inode_data_inline(inode, di);
+
+	if (!PageUptodate(page)) {
+		ret = ocfs2_read_inline_data(inode, page, wc->w_di_bh);
+		if (ret) {
+			ocfs2_commit_trans(osb, handle);
+
+			goto out;
+		}
+	}
+
+	wc->w_handle = handle;
+out:
+	return ret;
+}
+
+int ocfs2_size_fits_inline_data(struct buffer_head *di_bh, u64 new_size)
+{
+	struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+
+	if (new_size < le16_to_cpu(di->id2.i_data.id_count))
+		return 1;
+	return 0;
+}
+
+static int ocfs2_try_to_write_inline_data(struct address_space *mapping,
+					  struct inode *inode, loff_t pos,
+					  unsigned len, struct page *mmap_page,
+					  struct ocfs2_write_ctxt *wc)
+{
+	int ret, written = 0;
+	loff_t end = pos + len;
+	struct ocfs2_inode_info *oi = OCFS2_I(inode);
+
+	mlog(0, "Inode %llu, write of %u bytes at off %llu. features: 0x%x\n",
+	     (unsigned long long)oi->ip_blkno, len, (unsigned long long)pos,
+	     oi->ip_dyn_features);
+
+	/*
+	 * Handle inodes which already have inline data 1st.
+	 */
+	if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+		if (mmap_page == NULL &&
+		    ocfs2_size_fits_inline_data(wc->w_di_bh, end))
+			goto do_inline_write;
+
+		/*
+		 * The write won't fit - we have to give this inode an
+		 * inline extent list now.
+		 */
+		ret = ocfs2_convert_inline_data_to_extents(inode, wc->w_di_bh);
+		if (ret)
+			mlog_errno(ret);
+		goto out;
+	}
+
+	/*
+	 * Check whether the inode can accept inline data.
+	 */
+	if (oi->ip_clusters != 0 || i_size_read(inode) != 0)
+		return 0;
+
+	/*
+	 * Check whether the write can fit.
+	 */
+	if (mmap_page || end > ocfs2_max_inline_data(inode->i_sb))
+		return 0;
+
+do_inline_write:
+	ret = ocfs2_write_begin_inline(mapping, inode, wc);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	/*
+	 * This signals to the caller that the data can be written
+	 * inline.
+	 */
+	written = 1;
+out:
+	return written ? written : ret;
+}
+
+/*
+ * This function only does anything for file systems which can't
+ * handle sparse files.
+ *
+ * What we want to do here is fill in any hole between the current end
+ * of allocation and the end of our write. That way the rest of the
+ * write path can treat it as an non-allocating write, which has no
+ * special case code for sparse/nonsparse files.
+ */
+static int ocfs2_expand_nonsparse_inode(struct inode *inode, loff_t pos,
+					unsigned len,
+					struct ocfs2_write_ctxt *wc)
+{
+	int ret;
+	struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+	loff_t newsize = pos + len;
+
+	if (ocfs2_sparse_alloc(osb))
+		return 0;
+
+	if (newsize <= i_size_read(inode))
+		return 0;
+
+	ret = ocfs2_extend_no_holes(inode, newsize, newsize - len);
+	if (ret)
+		mlog_errno(ret);
+
+	return ret;
+}
+
 int ocfs2_write_begin_nolock(struct address_space *mapping,
 			     loff_t pos, unsigned len, unsigned flags,
 			     struct page **pagep, void **fsdata,
@@ -1381,6 +1607,25 @@
 		return ret;
 	}
 
+	if (ocfs2_supports_inline_data(osb)) {
+		ret = ocfs2_try_to_write_inline_data(mapping, inode, pos, len,
+						     mmap_page, wc);
+		if (ret == 1) {
+			ret = 0;
+			goto success;
+		}
+		if (ret < 0) {
+			mlog_errno(ret);
+			goto out;
+		}
+	}
+
+	ret = ocfs2_expand_nonsparse_inode(inode, pos, len, wc);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
 	ret = ocfs2_populate_write_desc(inode, wc, &clusters_to_alloc,
 					&extents_to_split);
 	if (ret) {
@@ -1462,6 +1707,7 @@
 	if (meta_ac)
 		ocfs2_free_alloc_context(meta_ac);
 
+success:
 	*pagep = wc->w_target_page;
 	*fsdata = wc;
 	return 0;
@@ -1529,6 +1775,31 @@
 	return ret;
 }
 
+static void ocfs2_write_end_inline(struct inode *inode, loff_t pos,
+				   unsigned len, unsigned *copied,
+				   struct ocfs2_dinode *di,
+				   struct ocfs2_write_ctxt *wc)
+{
+	void *kaddr;
+
+	if (unlikely(*copied < len)) {
+		if (!PageUptodate(wc->w_target_page)) {
+			*copied = 0;
+			return;
+		}
+	}
+
+	kaddr = kmap_atomic(wc->w_target_page, KM_USER0);
+	memcpy(di->id2.i_data.id_data + pos, kaddr + pos, *copied);
+	kunmap_atomic(kaddr, KM_USER0);
+
+	mlog(0, "Data written to inode at offset %llu. "
+	     "id_count = %u, copied = %u, i_dyn_features = 0x%x\n",
+	     (unsigned long long)pos, *copied,
+	     le16_to_cpu(di->id2.i_data.id_count),
+	     le16_to_cpu(di->i_dyn_features));
+}
+
 int ocfs2_write_end_nolock(struct address_space *mapping,
 			   loff_t pos, unsigned len, unsigned copied,
 			   struct page *page, void *fsdata)
@@ -1542,6 +1813,11 @@
 	handle_t *handle = wc->w_handle;
 	struct page *tmppage;
 
+	if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+		ocfs2_write_end_inline(inode, pos, len, &copied, di, wc);
+		goto out_write_size;
+	}
+
 	if (unlikely(copied < len)) {
 		if (!PageUptodate(wc->w_target_page))
 			copied = 0;
@@ -1579,6 +1855,7 @@
 		block_commit_write(tmppage, from, to);
 	}
 
+out_write_size:
 	pos += copied;
 	if (pos > inode->i_size) {
 		i_size_write(inode, pos);
diff --git a/fs/ocfs2/aops.h b/fs/ocfs2/aops.h
index 389579b..1135608 100644
--- a/fs/ocfs2/aops.h
+++ b/fs/ocfs2/aops.h
@@ -34,6 +34,8 @@
 			  struct inode *inode, unsigned int from,
 			  unsigned int to, int new);
 
+void ocfs2_unlock_and_free_pages(struct page **pages, int num_pages);
+
 int walk_page_buffers(	handle_t *handle,
 			struct buffer_head *head,
 			unsigned from,
@@ -59,6 +61,10 @@
 			     struct page **pagep, void **fsdata,
 			     struct buffer_head *di_bh, struct page *mmap_page);
 
+int ocfs2_read_inline_data(struct inode *inode, struct page *page,
+			   struct buffer_head *di_bh);
+int ocfs2_size_fits_inline_data(struct buffer_head *di_bh, u64 new_size);
+
 /* all ocfs2_dio_end_io()'s fault */
 #define ocfs2_iocb_is_rw_locked(iocb) \
 	test_bit(0, (unsigned long *)&iocb->private)
diff --git a/fs/ocfs2/cluster/masklog.c b/fs/ocfs2/cluster/masklog.c
index e9e042b..a4882c8 100644
--- a/fs/ocfs2/cluster/masklog.c
+++ b/fs/ocfs2/cluster/masklog.c
@@ -143,7 +143,7 @@
 };
 
 static struct kset mlog_kset = {
-	.kobj   = {.name = "logmask", .ktype = &mlog_ktype},
+	.kobj   = {.ktype = &mlog_ktype},
 };
 
 int mlog_sys_init(struct kset *o2cb_subsys)
@@ -156,6 +156,7 @@
 	}
 	mlog_attr_ptrs[i] = NULL;
 
+	kobject_set_name(&mlog_kset.kobj, "logmask");
 	kobj_set_kset_s(&mlog_kset, *o2cb_subsys);
 	return kset_register(&mlog_kset);
 }
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c
index 0d5fdde..7453b70 100644
--- a/fs/ocfs2/dir.c
+++ b/fs/ocfs2/dir.c
@@ -55,10 +55,16 @@
 #include "journal.h"
 #include "namei.h"
 #include "suballoc.h"
+#include "super.h"
 #include "uptodate.h"
 
 #include "buffer_head_io.h"
 
+#define NAMEI_RA_CHUNKS  2
+#define NAMEI_RA_BLOCKS  4
+#define NAMEI_RA_SIZE        (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS)
+#define NAMEI_RA_INDEX(c,b)  (((c) * NAMEI_RA_BLOCKS) + (b))
+
 static unsigned char ocfs2_filetype_table[] = {
 	DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
 };
@@ -66,12 +72,614 @@
 static int ocfs2_extend_dir(struct ocfs2_super *osb,
 			    struct inode *dir,
 			    struct buffer_head *parent_fe_bh,
+			    unsigned int blocks_wanted,
 			    struct buffer_head **new_de_bh);
+static int ocfs2_do_extend_dir(struct super_block *sb,
+			       handle_t *handle,
+			       struct inode *dir,
+			       struct buffer_head *parent_fe_bh,
+			       struct ocfs2_alloc_context *data_ac,
+			       struct ocfs2_alloc_context *meta_ac,
+			       struct buffer_head **new_bh);
+
 /*
- * ocfs2_readdir()
- *
+ * bh passed here can be an inode block or a dir data block, depending
+ * on the inode inline data flag.
  */
-int ocfs2_readdir(struct file * filp, void * dirent, filldir_t filldir)
+static int ocfs2_check_dir_entry(struct inode * dir,
+				 struct ocfs2_dir_entry * de,
+				 struct buffer_head * bh,
+				 unsigned long offset)
+{
+	const char *error_msg = NULL;
+	const int rlen = le16_to_cpu(de->rec_len);
+
+	if (rlen < OCFS2_DIR_REC_LEN(1))
+		error_msg = "rec_len is smaller than minimal";
+	else if (rlen % 4 != 0)
+		error_msg = "rec_len % 4 != 0";
+	else if (rlen < OCFS2_DIR_REC_LEN(de->name_len))
+		error_msg = "rec_len is too small for name_len";
+	else if (((char *) de - bh->b_data) + rlen > dir->i_sb->s_blocksize)
+		error_msg = "directory entry across blocks";
+
+	if (error_msg != NULL)
+		mlog(ML_ERROR, "bad entry in directory #%llu: %s - "
+		     "offset=%lu, inode=%llu, rec_len=%d, name_len=%d\n",
+		     (unsigned long long)OCFS2_I(dir)->ip_blkno, error_msg,
+		     offset, (unsigned long long)le64_to_cpu(de->inode), rlen,
+		     de->name_len);
+	return error_msg == NULL ? 1 : 0;
+}
+
+static inline int ocfs2_match(int len,
+			      const char * const name,
+			      struct ocfs2_dir_entry *de)
+{
+	if (len != de->name_len)
+		return 0;
+	if (!de->inode)
+		return 0;
+	return !memcmp(name, de->name, len);
+}
+
+/*
+ * Returns 0 if not found, -1 on failure, and 1 on success
+ */
+static int inline ocfs2_search_dirblock(struct buffer_head *bh,
+					struct inode *dir,
+					const char *name, int namelen,
+					unsigned long offset,
+					char *first_de,
+					unsigned int bytes,
+					struct ocfs2_dir_entry **res_dir)
+{
+	struct ocfs2_dir_entry *de;
+	char *dlimit, *de_buf;
+	int de_len;
+	int ret = 0;
+
+	mlog_entry_void();
+
+	de_buf = first_de;
+	dlimit = de_buf + bytes;
+
+	while (de_buf < dlimit) {
+		/* this code is executed quadratically often */
+		/* do minimal checking `by hand' */
+
+		de = (struct ocfs2_dir_entry *) de_buf;
+
+		if (de_buf + namelen <= dlimit &&
+		    ocfs2_match(namelen, name, de)) {
+			/* found a match - just to be sure, do a full check */
+			if (!ocfs2_check_dir_entry(dir, de, bh, offset)) {
+				ret = -1;
+				goto bail;
+			}
+			*res_dir = de;
+			ret = 1;
+			goto bail;
+		}
+
+		/* prevent looping on a bad block */
+		de_len = le16_to_cpu(de->rec_len);
+		if (de_len <= 0) {
+			ret = -1;
+			goto bail;
+		}
+
+		de_buf += de_len;
+		offset += de_len;
+	}
+
+bail:
+	mlog_exit(ret);
+	return ret;
+}
+
+static struct buffer_head *ocfs2_find_entry_id(const char *name,
+					       int namelen,
+					       struct inode *dir,
+					       struct ocfs2_dir_entry **res_dir)
+{
+	int ret, found;
+	struct buffer_head *di_bh = NULL;
+	struct ocfs2_dinode *di;
+	struct ocfs2_inline_data *data;
+
+	ret = ocfs2_read_block(OCFS2_SB(dir->i_sb), OCFS2_I(dir)->ip_blkno,
+			       &di_bh, OCFS2_BH_CACHED, dir);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	di = (struct ocfs2_dinode *)di_bh->b_data;
+	data = &di->id2.i_data;
+
+	found = ocfs2_search_dirblock(di_bh, dir, name, namelen, 0,
+				      data->id_data, i_size_read(dir), res_dir);
+	if (found == 1)
+		return di_bh;
+
+	brelse(di_bh);
+out:
+	return NULL;
+}
+
+struct buffer_head *ocfs2_find_entry_el(const char *name, int namelen,
+					struct inode *dir,
+					struct ocfs2_dir_entry **res_dir)
+{
+	struct super_block *sb;
+	struct buffer_head *bh_use[NAMEI_RA_SIZE];
+	struct buffer_head *bh, *ret = NULL;
+	unsigned long start, block, b;
+	int ra_max = 0;		/* Number of bh's in the readahead
+				   buffer, bh_use[] */
+	int ra_ptr = 0;		/* Current index into readahead
+				   buffer */
+	int num = 0;
+	int nblocks, i, err;
+
+	mlog_entry_void();
+
+	sb = dir->i_sb;
+
+	nblocks = i_size_read(dir) >> sb->s_blocksize_bits;
+	start = OCFS2_I(dir)->ip_dir_start_lookup;
+	if (start >= nblocks)
+		start = 0;
+	block = start;
+
+restart:
+	do {
+		/*
+		 * We deal with the read-ahead logic here.
+		 */
+		if (ra_ptr >= ra_max) {
+			/* Refill the readahead buffer */
+			ra_ptr = 0;
+			b = block;
+			for (ra_max = 0; ra_max < NAMEI_RA_SIZE; ra_max++) {
+				/*
+				 * Terminate if we reach the end of the
+				 * directory and must wrap, or if our
+				 * search has finished at this block.
+				 */
+				if (b >= nblocks || (num && block == start)) {
+					bh_use[ra_max] = NULL;
+					break;
+				}
+				num++;
+
+				bh = ocfs2_bread(dir, b++, &err, 1);
+				bh_use[ra_max] = bh;
+			}
+		}
+		if ((bh = bh_use[ra_ptr++]) == NULL)
+			goto next;
+		wait_on_buffer(bh);
+		if (!buffer_uptodate(bh)) {
+			/* read error, skip block & hope for the best */
+			ocfs2_error(dir->i_sb, "reading directory %llu, "
+				    "offset %lu\n",
+				    (unsigned long long)OCFS2_I(dir)->ip_blkno,
+				    block);
+			brelse(bh);
+			goto next;
+		}
+		i = ocfs2_search_dirblock(bh, dir, name, namelen,
+					  block << sb->s_blocksize_bits,
+					  bh->b_data, sb->s_blocksize,
+					  res_dir);
+		if (i == 1) {
+			OCFS2_I(dir)->ip_dir_start_lookup = block;
+			ret = bh;
+			goto cleanup_and_exit;
+		} else {
+			brelse(bh);
+			if (i < 0)
+				goto cleanup_and_exit;
+		}
+	next:
+		if (++block >= nblocks)
+			block = 0;
+	} while (block != start);
+
+	/*
+	 * If the directory has grown while we were searching, then
+	 * search the last part of the directory before giving up.
+	 */
+	block = nblocks;
+	nblocks = i_size_read(dir) >> sb->s_blocksize_bits;
+	if (block < nblocks) {
+		start = 0;
+		goto restart;
+	}
+
+cleanup_and_exit:
+	/* Clean up the read-ahead blocks */
+	for (; ra_ptr < ra_max; ra_ptr++)
+		brelse(bh_use[ra_ptr]);
+
+	mlog_exit_ptr(ret);
+	return ret;
+}
+
+/*
+ * Try to find an entry of the provided name within 'dir'.
+ *
+ * If nothing was found, NULL is returned. Otherwise, a buffer_head
+ * and pointer to the dir entry are passed back.
+ *
+ * Caller can NOT assume anything about the contents of the
+ * buffer_head - it is passed back only so that it can be passed into
+ * any one of the manipulation functions (add entry, delete entry,
+ * etc). As an example, bh in the extent directory case is a data
+ * block, in the inline-data case it actually points to an inode.
+ */
+struct buffer_head *ocfs2_find_entry(const char *name, int namelen,
+				     struct inode *dir,
+				     struct ocfs2_dir_entry **res_dir)
+{
+	*res_dir = NULL;
+
+	if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
+		return ocfs2_find_entry_id(name, namelen, dir, res_dir);
+
+	return ocfs2_find_entry_el(name, namelen, dir, res_dir);
+}
+
+/*
+ * Update inode number and type of a previously found directory entry.
+ */
+int ocfs2_update_entry(struct inode *dir, handle_t *handle,
+		       struct buffer_head *de_bh, struct ocfs2_dir_entry *de,
+		       struct inode *new_entry_inode)
+{
+	int ret;
+
+	/*
+	 * The same code works fine for both inline-data and extent
+	 * based directories, so no need to split this up.
+	 */
+
+	ret = ocfs2_journal_access(handle, dir, de_bh,
+				   OCFS2_JOURNAL_ACCESS_WRITE);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	de->inode = cpu_to_le64(OCFS2_I(new_entry_inode)->ip_blkno);
+	ocfs2_set_de_type(de, new_entry_inode->i_mode);
+
+	ocfs2_journal_dirty(handle, de_bh);
+
+out:
+	return ret;
+}
+
+static int __ocfs2_delete_entry(handle_t *handle, struct inode *dir,
+				struct ocfs2_dir_entry *de_del,
+				struct buffer_head *bh, char *first_de,
+				unsigned int bytes)
+{
+	struct ocfs2_dir_entry *de, *pde;
+	int i, status = -ENOENT;
+
+	mlog_entry("(0x%p, 0x%p, 0x%p, 0x%p)\n", handle, dir, de_del, bh);
+
+	i = 0;
+	pde = NULL;
+	de = (struct ocfs2_dir_entry *) first_de;
+	while (i < bytes) {
+		if (!ocfs2_check_dir_entry(dir, de, bh, i)) {
+			status = -EIO;
+			mlog_errno(status);
+			goto bail;
+		}
+		if (de == de_del)  {
+			status = ocfs2_journal_access(handle, dir, bh,
+						      OCFS2_JOURNAL_ACCESS_WRITE);
+			if (status < 0) {
+				status = -EIO;
+				mlog_errno(status);
+				goto bail;
+			}
+			if (pde)
+				pde->rec_len =
+					cpu_to_le16(le16_to_cpu(pde->rec_len) +
+						    le16_to_cpu(de->rec_len));
+			else
+				de->inode = 0;
+			dir->i_version++;
+			status = ocfs2_journal_dirty(handle, bh);
+			goto bail;
+		}
+		i += le16_to_cpu(de->rec_len);
+		pde = de;
+		de = (struct ocfs2_dir_entry *)((char *)de + le16_to_cpu(de->rec_len));
+	}
+bail:
+	mlog_exit(status);
+	return status;
+}
+
+static inline int ocfs2_delete_entry_id(handle_t *handle,
+					struct inode *dir,
+					struct ocfs2_dir_entry *de_del,
+					struct buffer_head *bh)
+{
+	int ret;
+	struct buffer_head *di_bh = NULL;
+	struct ocfs2_dinode *di;
+	struct ocfs2_inline_data *data;
+
+	ret = ocfs2_read_block(OCFS2_SB(dir->i_sb), OCFS2_I(dir)->ip_blkno,
+			       &di_bh, OCFS2_BH_CACHED, dir);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	di = (struct ocfs2_dinode *)di_bh->b_data;
+	data = &di->id2.i_data;
+
+	ret = __ocfs2_delete_entry(handle, dir, de_del, bh, data->id_data,
+				   i_size_read(dir));
+
+	brelse(di_bh);
+out:
+	return ret;
+}
+
+static inline int ocfs2_delete_entry_el(handle_t *handle,
+					struct inode *dir,
+					struct ocfs2_dir_entry *de_del,
+					struct buffer_head *bh)
+{
+	return __ocfs2_delete_entry(handle, dir, de_del, bh, bh->b_data,
+				    bh->b_size);
+}
+
+/*
+ * ocfs2_delete_entry deletes a directory entry by merging it with the
+ * previous entry
+ */
+int ocfs2_delete_entry(handle_t *handle,
+		       struct inode *dir,
+		       struct ocfs2_dir_entry *de_del,
+		       struct buffer_head *bh)
+{
+	if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
+		return ocfs2_delete_entry_id(handle, dir, de_del, bh);
+
+	return ocfs2_delete_entry_el(handle, dir, de_del, bh);
+}
+
+/*
+ * Check whether 'de' has enough room to hold an entry of
+ * 'new_rec_len' bytes.
+ */
+static inline int ocfs2_dirent_would_fit(struct ocfs2_dir_entry *de,
+					 unsigned int new_rec_len)
+{
+	unsigned int de_really_used;
+
+	/* Check whether this is an empty record with enough space */
+	if (le64_to_cpu(de->inode) == 0 &&
+	    le16_to_cpu(de->rec_len) >= new_rec_len)
+		return 1;
+
+	/*
+	 * Record might have free space at the end which we can
+	 * use.
+	 */
+	de_really_used = OCFS2_DIR_REC_LEN(de->name_len);
+	if (le16_to_cpu(de->rec_len) >= (de_really_used + new_rec_len))
+	    return 1;
+
+	return 0;
+}
+
+/* we don't always have a dentry for what we want to add, so people
+ * like orphan dir can call this instead.
+ *
+ * If you pass me insert_bh, I'll skip the search of the other dir
+ * blocks and put the record in there.
+ */
+int __ocfs2_add_entry(handle_t *handle,
+		      struct inode *dir,
+		      const char *name, int namelen,
+		      struct inode *inode, u64 blkno,
+		      struct buffer_head *parent_fe_bh,
+		      struct buffer_head *insert_bh)
+{
+	unsigned long offset;
+	unsigned short rec_len;
+	struct ocfs2_dir_entry *de, *de1;
+	struct ocfs2_dinode *di = (struct ocfs2_dinode *)parent_fe_bh->b_data;
+	struct super_block *sb = dir->i_sb;
+	int retval, status;
+	unsigned int size = sb->s_blocksize;
+	char *data_start = insert_bh->b_data;
+
+	mlog_entry_void();
+
+	if (!namelen)
+		return -EINVAL;
+
+	if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+		data_start = di->id2.i_data.id_data;
+		size = i_size_read(dir);
+
+		BUG_ON(insert_bh != parent_fe_bh);
+	}
+
+	rec_len = OCFS2_DIR_REC_LEN(namelen);
+	offset = 0;
+	de = (struct ocfs2_dir_entry *) data_start;
+	while (1) {
+		BUG_ON((char *)de >= (size + data_start));
+
+		/* These checks should've already been passed by the
+		 * prepare function, but I guess we can leave them
+		 * here anyway. */
+		if (!ocfs2_check_dir_entry(dir, de, insert_bh, offset)) {
+			retval = -ENOENT;
+			goto bail;
+		}
+		if (ocfs2_match(namelen, name, de)) {
+			retval = -EEXIST;
+			goto bail;
+		}
+
+		if (ocfs2_dirent_would_fit(de, rec_len)) {
+			dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+			retval = ocfs2_mark_inode_dirty(handle, dir, parent_fe_bh);
+			if (retval < 0) {
+				mlog_errno(retval);
+				goto bail;
+			}
+
+			status = ocfs2_journal_access(handle, dir, insert_bh,
+						      OCFS2_JOURNAL_ACCESS_WRITE);
+			/* By now the buffer is marked for journaling */
+			offset += le16_to_cpu(de->rec_len);
+			if (le64_to_cpu(de->inode)) {
+				de1 = (struct ocfs2_dir_entry *)((char *) de +
+					OCFS2_DIR_REC_LEN(de->name_len));
+				de1->rec_len =
+					cpu_to_le16(le16_to_cpu(de->rec_len) -
+					OCFS2_DIR_REC_LEN(de->name_len));
+				de->rec_len = cpu_to_le16(OCFS2_DIR_REC_LEN(de->name_len));
+				de = de1;
+			}
+			de->file_type = OCFS2_FT_UNKNOWN;
+			if (blkno) {
+				de->inode = cpu_to_le64(blkno);
+				ocfs2_set_de_type(de, inode->i_mode);
+			} else
+				de->inode = 0;
+			de->name_len = namelen;
+			memcpy(de->name, name, namelen);
+
+			dir->i_version++;
+			status = ocfs2_journal_dirty(handle, insert_bh);
+			retval = 0;
+			goto bail;
+		}
+		offset += le16_to_cpu(de->rec_len);
+		de = (struct ocfs2_dir_entry *) ((char *) de + le16_to_cpu(de->rec_len));
+	}
+
+	/* when you think about it, the assert above should prevent us
+	 * from ever getting here. */
+	retval = -ENOSPC;
+bail:
+
+	mlog_exit(retval);
+	return retval;
+}
+
+static int ocfs2_dir_foreach_blk_id(struct inode *inode,
+				    unsigned long *f_version,
+				    loff_t *f_pos, void *priv,
+				    filldir_t filldir, int *filldir_err)
+{
+	int ret, i, filldir_ret;
+	unsigned long offset = *f_pos;
+	struct buffer_head *di_bh = NULL;
+	struct ocfs2_dinode *di;
+	struct ocfs2_inline_data *data;
+	struct ocfs2_dir_entry *de;
+
+	ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), OCFS2_I(inode)->ip_blkno,
+			       &di_bh, OCFS2_BH_CACHED, inode);
+	if (ret) {
+		mlog(ML_ERROR, "Unable to read inode block for dir %llu\n",
+		     (unsigned long long)OCFS2_I(inode)->ip_blkno);
+		goto out;
+	}
+
+	di = (struct ocfs2_dinode *)di_bh->b_data;
+	data = &di->id2.i_data;
+
+	while (*f_pos < i_size_read(inode)) {
+revalidate:
+		/* If the dir block has changed since the last call to
+		 * readdir(2), then we might be pointing to an invalid
+		 * dirent right now.  Scan from the start of the block
+		 * to make sure. */
+		if (*f_version != inode->i_version) {
+			for (i = 0; i < i_size_read(inode) && i < offset; ) {
+				de = (struct ocfs2_dir_entry *)
+					(data->id_data + i);
+				/* It's too expensive to do a full
+				 * dirent test each time round this
+				 * loop, but we do have to test at
+				 * least that it is non-zero.  A
+				 * failure will be detected in the
+				 * dirent test below. */
+				if (le16_to_cpu(de->rec_len) <
+				    OCFS2_DIR_REC_LEN(1))
+					break;
+				i += le16_to_cpu(de->rec_len);
+			}
+			*f_pos = offset = i;
+			*f_version = inode->i_version;
+		}
+
+		de = (struct ocfs2_dir_entry *) (data->id_data + *f_pos);
+		if (!ocfs2_check_dir_entry(inode, de, di_bh, *f_pos)) {
+			/* On error, skip the f_pos to the end. */
+			*f_pos = i_size_read(inode);
+			goto out;
+		}
+		offset += le16_to_cpu(de->rec_len);
+		if (le64_to_cpu(de->inode)) {
+			/* We might block in the next section
+			 * if the data destination is
+			 * currently swapped out.  So, use a
+			 * version stamp to detect whether or
+			 * not the directory has been modified
+			 * during the copy operation.
+			 */
+			unsigned long version = *f_version;
+			unsigned char d_type = DT_UNKNOWN;
+
+			if (de->file_type < OCFS2_FT_MAX)
+				d_type = ocfs2_filetype_table[de->file_type];
+
+			filldir_ret = filldir(priv, de->name,
+					      de->name_len,
+					      *f_pos,
+					      le64_to_cpu(de->inode),
+					      d_type);
+			if (filldir_ret) {
+				if (filldir_err)
+					*filldir_err = filldir_ret;
+				break;
+			}
+			if (version != *f_version)
+				goto revalidate;
+		}
+		*f_pos += le16_to_cpu(de->rec_len);
+	}
+
+out:
+	brelse(di_bh);
+
+	return 0;
+}
+
+static int ocfs2_dir_foreach_blk_el(struct inode *inode,
+				    unsigned long *f_version,
+				    loff_t *f_pos, void *priv,
+				    filldir_t filldir, int *filldir_err)
 {
 	int error = 0;
 	unsigned long offset, blk, last_ra_blk = 0;
@@ -79,45 +687,23 @@
 	struct buffer_head * bh, * tmp;
 	struct ocfs2_dir_entry * de;
 	int err;
-	struct inode *inode = filp->f_path.dentry->d_inode;
 	struct super_block * sb = inode->i_sb;
 	unsigned int ra_sectors = 16;
-	int lock_level = 0;
-
-	mlog_entry("dirino=%llu\n",
-		   (unsigned long long)OCFS2_I(inode)->ip_blkno);
 
 	stored = 0;
 	bh = NULL;
 
-	error = ocfs2_meta_lock_atime(inode, filp->f_vfsmnt, &lock_level);
-	if (lock_level && error >= 0) {
-		/* We release EX lock which used to update atime
-		 * and get PR lock again to reduce contention
-		 * on commonly accessed directories. */
-		ocfs2_meta_unlock(inode, 1);
-		lock_level = 0;
-		error = ocfs2_meta_lock(inode, NULL, 0);
-	}
-	if (error < 0) {
-		if (error != -ENOENT)
-			mlog_errno(error);
-		/* we haven't got any yet, so propagate the error. */
-		stored = error;
-		goto bail_nolock;
-	}
+	offset = (*f_pos) & (sb->s_blocksize - 1);
 
-	offset = filp->f_pos & (sb->s_blocksize - 1);
-
-	while (!error && !stored && filp->f_pos < i_size_read(inode)) {
-		blk = (filp->f_pos) >> sb->s_blocksize_bits;
+	while (!error && !stored && *f_pos < i_size_read(inode)) {
+		blk = (*f_pos) >> sb->s_blocksize_bits;
 		bh = ocfs2_bread(inode, blk, &err, 0);
 		if (!bh) {
 			mlog(ML_ERROR,
 			     "directory #%llu contains a hole at offset %lld\n",
 			     (unsigned long long)OCFS2_I(inode)->ip_blkno,
-			     filp->f_pos);
-			filp->f_pos += sb->s_blocksize - offset;
+			     *f_pos);
+			*f_pos += sb->s_blocksize - offset;
 			continue;
 		}
 
@@ -143,7 +729,7 @@
 		 * readdir(2), then we might be pointing to an invalid
 		 * dirent right now.  Scan from the start of the block
 		 * to make sure. */
-		if (filp->f_version != inode->i_version) {
+		if (*f_version != inode->i_version) {
 			for (i = 0; i < sb->s_blocksize && i < offset; ) {
 				de = (struct ocfs2_dir_entry *) (bh->b_data + i);
 				/* It's too expensive to do a full
@@ -158,21 +744,20 @@
 				i += le16_to_cpu(de->rec_len);
 			}
 			offset = i;
-			filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
+			*f_pos = ((*f_pos) & ~(sb->s_blocksize - 1))
 				| offset;
-			filp->f_version = inode->i_version;
+			*f_version = inode->i_version;
 		}
 
-		while (!error && filp->f_pos < i_size_read(inode)
+		while (!error && *f_pos < i_size_read(inode)
 		       && offset < sb->s_blocksize) {
 			de = (struct ocfs2_dir_entry *) (bh->b_data + offset);
 			if (!ocfs2_check_dir_entry(inode, de, bh, offset)) {
 				/* On error, skip the f_pos to the
 				   next block. */
-				filp->f_pos = (filp->f_pos |
-					       (sb->s_blocksize - 1)) + 1;
+				*f_pos = ((*f_pos) | (sb->s_blocksize - 1)) + 1;
 				brelse(bh);
-				goto bail;
+				goto out;
 			}
 			offset += le16_to_cpu(de->rec_len);
 			if (le64_to_cpu(de->inode)) {
@@ -183,36 +768,109 @@
 				 * not the directory has been modified
 				 * during the copy operation.
 				 */
-				unsigned long version = filp->f_version;
+				unsigned long version = *f_version;
 				unsigned char d_type = DT_UNKNOWN;
 
 				if (de->file_type < OCFS2_FT_MAX)
 					d_type = ocfs2_filetype_table[de->file_type];
-				error = filldir(dirent, de->name,
+				error = filldir(priv, de->name,
 						de->name_len,
-						filp->f_pos,
-						ino_from_blkno(sb, le64_to_cpu(de->inode)),
+						*f_pos,
+						le64_to_cpu(de->inode),
 						d_type);
-				if (error)
+				if (error) {
+					if (filldir_err)
+						*filldir_err = error;
 					break;
-				if (version != filp->f_version)
+				}
+				if (version != *f_version)
 					goto revalidate;
 				stored ++;
 			}
-			filp->f_pos += le16_to_cpu(de->rec_len);
+			*f_pos += le16_to_cpu(de->rec_len);
 		}
 		offset = 0;
 		brelse(bh);
 	}
 
 	stored = 0;
-bail:
+out:
+	return stored;
+}
+
+static int ocfs2_dir_foreach_blk(struct inode *inode, unsigned long *f_version,
+				 loff_t *f_pos, void *priv, filldir_t filldir,
+				 int *filldir_err)
+{
+	if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
+		return ocfs2_dir_foreach_blk_id(inode, f_version, f_pos, priv,
+						filldir, filldir_err);
+
+	return ocfs2_dir_foreach_blk_el(inode, f_version, f_pos, priv, filldir,
+					filldir_err);
+}
+
+/*
+ * This is intended to be called from inside other kernel functions,
+ * so we fake some arguments.
+ */
+int ocfs2_dir_foreach(struct inode *inode, loff_t *f_pos, void *priv,
+		      filldir_t filldir)
+{
+	int ret = 0, filldir_err = 0;
+	unsigned long version = inode->i_version;
+
+	while (*f_pos < i_size_read(inode)) {
+		ret = ocfs2_dir_foreach_blk(inode, &version, f_pos, priv,
+					    filldir, &filldir_err);
+		if (ret || filldir_err)
+			break;
+	}
+
+	if (ret > 0)
+		ret = -EIO;
+
+	return 0;
+}
+
+/*
+ * ocfs2_readdir()
+ *
+ */
+int ocfs2_readdir(struct file * filp, void * dirent, filldir_t filldir)
+{
+	int error = 0;
+	struct inode *inode = filp->f_path.dentry->d_inode;
+	int lock_level = 0;
+
+	mlog_entry("dirino=%llu\n",
+		   (unsigned long long)OCFS2_I(inode)->ip_blkno);
+
+	error = ocfs2_meta_lock_atime(inode, filp->f_vfsmnt, &lock_level);
+	if (lock_level && error >= 0) {
+		/* We release EX lock which used to update atime
+		 * and get PR lock again to reduce contention
+		 * on commonly accessed directories. */
+		ocfs2_meta_unlock(inode, 1);
+		lock_level = 0;
+		error = ocfs2_meta_lock(inode, NULL, 0);
+	}
+	if (error < 0) {
+		if (error != -ENOENT)
+			mlog_errno(error);
+		/* we haven't got any yet, so propagate the error. */
+		goto bail_nolock;
+	}
+
+	error = ocfs2_dir_foreach_blk(inode, &filp->f_version, &filp->f_pos,
+				      dirent, filldir, NULL);
+
 	ocfs2_meta_unlock(inode, lock_level);
 
 bail_nolock:
-	mlog_exit(stored);
+	mlog_exit(error);
 
-	return stored;
+	return error;
 }
 
 /*
@@ -252,6 +910,23 @@
 	return status;
 }
 
+/*
+ * Convenience function for callers which just want the block number
+ * mapped to a name and don't require the full dirent info, etc.
+ */
+int ocfs2_lookup_ino_from_name(struct inode *dir, const char *name,
+			       int namelen, u64 *blkno)
+{
+	int ret;
+	struct buffer_head *bh = NULL;
+	struct ocfs2_dir_entry *dirent = NULL;
+
+	ret = ocfs2_find_files_on_disk(name, namelen, blkno, dir, &bh, &dirent);
+	brelse(bh);
+
+	return ret;
+}
+
 /* Check for a name within a directory.
  *
  * Return 0 if the name does not exist
@@ -284,77 +959,414 @@
 	return ret;
 }
 
+struct ocfs2_empty_dir_priv {
+	unsigned seen_dot;
+	unsigned seen_dot_dot;
+	unsigned seen_other;
+};
+static int ocfs2_empty_dir_filldir(void *priv, const char *name, int name_len,
+				   loff_t pos, u64 ino, unsigned type)
+{
+	struct ocfs2_empty_dir_priv *p = priv;
+
+	/*
+	 * Check the positions of "." and ".." records to be sure
+	 * they're in the correct place.
+	 */
+	if (name_len == 1 && !strncmp(".", name, 1) && pos == 0) {
+		p->seen_dot = 1;
+		return 0;
+	}
+
+	if (name_len == 2 && !strncmp("..", name, 2) &&
+	    pos == OCFS2_DIR_REC_LEN(1)) {
+		p->seen_dot_dot = 1;
+		return 0;
+	}
+
+	p->seen_other = 1;
+	return 1;
+}
 /*
  * routine to check that the specified directory is empty (for rmdir)
+ *
+ * Returns 1 if dir is empty, zero otherwise.
  */
 int ocfs2_empty_dir(struct inode *inode)
 {
-	unsigned long offset;
-	struct buffer_head * bh;
-	struct ocfs2_dir_entry * de, * de1;
-	struct super_block * sb;
-	int err;
+	int ret;
+	loff_t start = 0;
+	struct ocfs2_empty_dir_priv priv;
 
-	sb = inode->i_sb;
-	if ((i_size_read(inode) <
-	     (OCFS2_DIR_REC_LEN(1) + OCFS2_DIR_REC_LEN(2))) ||
-	    !(bh = ocfs2_bread(inode, 0, &err, 0))) {
-	    	mlog(ML_ERROR, "bad directory (dir #%llu) - no data block\n",
+	memset(&priv, 0, sizeof(priv));
+
+	ret = ocfs2_dir_foreach(inode, &start, &priv, ocfs2_empty_dir_filldir);
+	if (ret)
+		mlog_errno(ret);
+
+	if (!priv.seen_dot || !priv.seen_dot_dot) {
+		mlog(ML_ERROR, "bad directory (dir #%llu) - no `.' or `..'\n",
 		     (unsigned long long)OCFS2_I(inode)->ip_blkno);
+		/*
+		 * XXX: Is it really safe to allow an unlink to continue?
+		 */
 		return 1;
 	}
 
-	de = (struct ocfs2_dir_entry *) bh->b_data;
-	de1 = (struct ocfs2_dir_entry *)
-			((char *)de + le16_to_cpu(de->rec_len));
-	if ((le64_to_cpu(de->inode) != OCFS2_I(inode)->ip_blkno) ||
-			!le64_to_cpu(de1->inode) ||
-			strcmp(".", de->name) ||
-			strcmp("..", de1->name)) {
-	    	mlog(ML_ERROR, "bad directory (dir #%llu) - no `.' or `..'\n",
-		     (unsigned long long)OCFS2_I(inode)->ip_blkno);
-		brelse(bh);
-		return 1;
+	return !priv.seen_other;
+}
+
+static void ocfs2_fill_initial_dirents(struct inode *inode,
+				       struct inode *parent,
+				       char *start, unsigned int size)
+{
+	struct ocfs2_dir_entry *de = (struct ocfs2_dir_entry *)start;
+
+	de->inode = cpu_to_le64(OCFS2_I(inode)->ip_blkno);
+	de->name_len = 1;
+	de->rec_len =
+		cpu_to_le16(OCFS2_DIR_REC_LEN(de->name_len));
+	strcpy(de->name, ".");
+	ocfs2_set_de_type(de, S_IFDIR);
+
+	de = (struct ocfs2_dir_entry *) ((char *)de + le16_to_cpu(de->rec_len));
+	de->inode = cpu_to_le64(OCFS2_I(parent)->ip_blkno);
+	de->rec_len = cpu_to_le16(size - OCFS2_DIR_REC_LEN(1));
+	de->name_len = 2;
+	strcpy(de->name, "..");
+	ocfs2_set_de_type(de, S_IFDIR);
+}
+
+/*
+ * This works together with code in ocfs2_mknod_locked() which sets
+ * the inline-data flag and initializes the inline-data section.
+ */
+static int ocfs2_fill_new_dir_id(struct ocfs2_super *osb,
+				 handle_t *handle,
+				 struct inode *parent,
+				 struct inode *inode,
+				 struct buffer_head *di_bh)
+{
+	int ret;
+	struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+	struct ocfs2_inline_data *data = &di->id2.i_data;
+	unsigned int size = le16_to_cpu(data->id_count);
+
+	ret = ocfs2_journal_access(handle, inode, di_bh,
+				   OCFS2_JOURNAL_ACCESS_WRITE);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
 	}
-	offset = le16_to_cpu(de->rec_len) + le16_to_cpu(de1->rec_len);
-	de = (struct ocfs2_dir_entry *)((char *)de1 + le16_to_cpu(de1->rec_len));
-	while (offset < i_size_read(inode) ) {
-		if (!bh || (void *)de >= (void *)(bh->b_data + sb->s_blocksize)) {
-			brelse(bh);
-			bh = ocfs2_bread(inode,
-					 offset >> sb->s_blocksize_bits, &err, 0);
-			if (!bh) {
-				mlog(ML_ERROR, "dir %llu has a hole at %lu\n",
-				     (unsigned long long)OCFS2_I(inode)->ip_blkno, offset);
-				offset += sb->s_blocksize;
-				continue;
-			}
-			de = (struct ocfs2_dir_entry *) bh->b_data;
-		}
-		if (!ocfs2_check_dir_entry(inode, de, bh, offset)) {
-			brelse(bh);
-			return 1;
-		}
-		if (le64_to_cpu(de->inode)) {
-			brelse(bh);
-			return 0;
-		}
-		offset += le16_to_cpu(de->rec_len);
-		de = (struct ocfs2_dir_entry *)
-			((char *)de + le16_to_cpu(de->rec_len));
+
+	ocfs2_fill_initial_dirents(inode, parent, data->id_data, size);
+
+	ocfs2_journal_dirty(handle, di_bh);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
 	}
-	brelse(bh);
-	return 1;
+
+	i_size_write(inode, size);
+	inode->i_nlink = 2;
+	inode->i_blocks = ocfs2_inode_sector_count(inode);
+
+	ret = ocfs2_mark_inode_dirty(handle, inode, di_bh);
+	if (ret < 0)
+		mlog_errno(ret);
+
+out:
+	return ret;
+}
+
+static int ocfs2_fill_new_dir_el(struct ocfs2_super *osb,
+				 handle_t *handle,
+				 struct inode *parent,
+				 struct inode *inode,
+				 struct buffer_head *fe_bh,
+				 struct ocfs2_alloc_context *data_ac)
+{
+	int status;
+	struct buffer_head *new_bh = NULL;
+
+	mlog_entry_void();
+
+	status = ocfs2_do_extend_dir(osb->sb, handle, inode, fe_bh,
+				     data_ac, NULL, &new_bh);
+	if (status < 0) {
+		mlog_errno(status);
+		goto bail;
+	}
+
+	ocfs2_set_new_buffer_uptodate(inode, new_bh);
+
+	status = ocfs2_journal_access(handle, inode, new_bh,
+				      OCFS2_JOURNAL_ACCESS_CREATE);
+	if (status < 0) {
+		mlog_errno(status);
+		goto bail;
+	}
+	memset(new_bh->b_data, 0, osb->sb->s_blocksize);
+
+	ocfs2_fill_initial_dirents(inode, parent, new_bh->b_data,
+				   osb->sb->s_blocksize);
+
+	status = ocfs2_journal_dirty(handle, new_bh);
+	if (status < 0) {
+		mlog_errno(status);
+		goto bail;
+	}
+
+	i_size_write(inode, inode->i_sb->s_blocksize);
+	inode->i_nlink = 2;
+	inode->i_blocks = ocfs2_inode_sector_count(inode);
+	status = ocfs2_mark_inode_dirty(handle, inode, fe_bh);
+	if (status < 0) {
+		mlog_errno(status);
+		goto bail;
+	}
+
+	status = 0;
+bail:
+	if (new_bh)
+		brelse(new_bh);
+
+	mlog_exit(status);
+	return status;
+}
+
+int ocfs2_fill_new_dir(struct ocfs2_super *osb,
+		       handle_t *handle,
+		       struct inode *parent,
+		       struct inode *inode,
+		       struct buffer_head *fe_bh,
+		       struct ocfs2_alloc_context *data_ac)
+{
+	BUG_ON(!ocfs2_supports_inline_data(osb) && data_ac == NULL);
+
+	if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
+		return ocfs2_fill_new_dir_id(osb, handle, parent, inode, fe_bh);
+
+	return ocfs2_fill_new_dir_el(osb, handle, parent, inode, fe_bh,
+				     data_ac);
+}
+
+static void ocfs2_expand_last_dirent(char *start, unsigned int old_size,
+				     unsigned int new_size)
+{
+	struct ocfs2_dir_entry *de;
+	struct ocfs2_dir_entry *prev_de;
+	char *de_buf, *limit;
+	unsigned int bytes = new_size - old_size;
+
+	limit = start + old_size;
+	de_buf = start;
+	de = (struct ocfs2_dir_entry *)de_buf;
+	do {
+		prev_de = de;
+		de_buf += le16_to_cpu(de->rec_len);
+		de = (struct ocfs2_dir_entry *)de_buf;
+	} while (de_buf < limit);
+
+	le16_add_cpu(&prev_de->rec_len, bytes);
+}
+
+/*
+ * We allocate enough clusters to fulfill "blocks_wanted", but set
+ * i_size to exactly one block. Ocfs2_extend_dir() will handle the
+ * rest automatically for us.
+ *
+ * *first_block_bh is a pointer to the 1st data block allocated to the
+ *  directory.
+ */
+static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
+				   unsigned int blocks_wanted,
+				   struct buffer_head **first_block_bh)
+{
+	int ret, credits = OCFS2_INLINE_TO_EXTENTS_CREDITS;
+	u32 alloc, bit_off, len;
+	struct super_block *sb = dir->i_sb;
+	u64 blkno, bytes = blocks_wanted << sb->s_blocksize_bits;
+	struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
+	struct ocfs2_inode_info *oi = OCFS2_I(dir);
+	struct ocfs2_alloc_context *data_ac;
+	struct buffer_head *dirdata_bh = NULL;
+	struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+	handle_t *handle;
+
+	alloc = ocfs2_clusters_for_bytes(sb, bytes);
+
+	/*
+	 * We should never need more than 2 clusters for this -
+	 * maximum dirent size is far less than one block. In fact,
+	 * the only time we'd need more than one cluster is if
+	 * blocksize == clustersize and the dirent won't fit in the
+	 * extra space that the expansion to a single block gives. As
+	 * of today, that only happens on 4k/4k file systems.
+	 */
+	BUG_ON(alloc > 2);
+
+	ret = ocfs2_reserve_clusters(osb, alloc, &data_ac);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	down_write(&oi->ip_alloc_sem);
+
+	/*
+	 * Prepare for worst case allocation scenario of two seperate
+	 * extents.
+	 */
+	if (alloc == 2)
+		credits += OCFS2_SUBALLOC_ALLOC;
+
+	handle = ocfs2_start_trans(osb, credits);
+	if (IS_ERR(handle)) {
+		ret = PTR_ERR(handle);
+		mlog_errno(ret);
+		goto out_sem;
+	}
+
+	/*
+	 * Try to claim as many clusters as the bitmap can give though
+	 * if we only get one now, that's enough to continue. The rest
+	 * will be claimed after the conversion to extents.
+	 */
+	ret = ocfs2_claim_clusters(osb, handle, data_ac, 1, &bit_off, &len);
+	if (ret) {
+		mlog_errno(ret);
+		goto out_commit;
+	}
+
+	/*
+	 * Operations are carefully ordered so that we set up the new
+	 * data block first. The conversion from inline data to
+	 * extents follows.
+	 */
+	blkno = ocfs2_clusters_to_blocks(dir->i_sb, bit_off);
+	dirdata_bh = sb_getblk(sb, blkno);
+	if (!dirdata_bh) {
+		ret = -EIO;
+		mlog_errno(ret);
+		goto out_commit;
+	}
+
+	ocfs2_set_new_buffer_uptodate(dir, dirdata_bh);
+
+	ret = ocfs2_journal_access(handle, dir, dirdata_bh,
+				   OCFS2_JOURNAL_ACCESS_CREATE);
+	if (ret) {
+		mlog_errno(ret);
+		goto out_commit;
+	}
+
+	memcpy(dirdata_bh->b_data, di->id2.i_data.id_data, i_size_read(dir));
+	memset(dirdata_bh->b_data + i_size_read(dir), 0,
+	       sb->s_blocksize - i_size_read(dir));
+	ocfs2_expand_last_dirent(dirdata_bh->b_data, i_size_read(dir),
+				 sb->s_blocksize);
+
+	ret = ocfs2_journal_dirty(handle, dirdata_bh);
+	if (ret) {
+		mlog_errno(ret);
+		goto out_commit;
+	}
+
+	/*
+	 * Set extent, i_size, etc on the directory. After this, the
+	 * inode should contain the same exact dirents as before and
+	 * be fully accessible from system calls.
+	 *
+	 * We let the later dirent insert modify c/mtime - to the user
+	 * the data hasn't changed.
+	 */
+	ret = ocfs2_journal_access(handle, dir, di_bh,
+				   OCFS2_JOURNAL_ACCESS_CREATE);
+	if (ret) {
+		mlog_errno(ret);
+		goto out_commit;
+	}
+
+	spin_lock(&oi->ip_lock);
+	oi->ip_dyn_features &= ~OCFS2_INLINE_DATA_FL;
+	di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features);
+	spin_unlock(&oi->ip_lock);
+
+	ocfs2_dinode_new_extent_list(dir, di);
+
+	i_size_write(dir, sb->s_blocksize);
+	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+
+	di->i_size = cpu_to_le64(sb->s_blocksize);
+	di->i_ctime = di->i_mtime = cpu_to_le64(dir->i_ctime.tv_sec);
+	di->i_ctime_nsec = di->i_mtime_nsec = cpu_to_le32(dir->i_ctime.tv_nsec);
+	dir->i_blocks = ocfs2_inode_sector_count(dir);
+
+	/*
+	 * This should never fail as our extent list is empty and all
+	 * related blocks have been journaled already.
+	 */
+	ret = ocfs2_insert_extent(osb, handle, dir, di_bh, 0, blkno, len, 0,
+				  NULL);
+	if (ret) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	ret = ocfs2_journal_dirty(handle, di_bh);
+	if (ret) {
+		mlog_errno(ret);
+		goto out_commit;
+	}
+
+	/*
+	 * We asked for two clusters, but only got one in the 1st
+	 * pass. Claim the 2nd cluster as a separate extent.
+	 */
+	if (alloc > len) {
+		ret = ocfs2_claim_clusters(osb, handle, data_ac, 1, &bit_off,
+					   &len);
+		if (ret) {
+			mlog_errno(ret);
+			goto out_commit;
+		}
+		blkno = ocfs2_clusters_to_blocks(dir->i_sb, bit_off);
+
+		ret = ocfs2_insert_extent(osb, handle, dir, di_bh, 1, blkno,
+					  len, 0, NULL);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+	}
+
+	*first_block_bh = dirdata_bh;
+	dirdata_bh = NULL;
+
+out_commit:
+	ocfs2_commit_trans(osb, handle);
+
+out_sem:
+	up_write(&oi->ip_alloc_sem);
+
+out:
+	if (data_ac)
+		ocfs2_free_alloc_context(data_ac);
+
+	brelse(dirdata_bh);
+
+	return ret;
 }
 
 /* returns a bh of the 1st new block in the allocation. */
-int ocfs2_do_extend_dir(struct super_block *sb,
-			handle_t *handle,
-			struct inode *dir,
-			struct buffer_head *parent_fe_bh,
-			struct ocfs2_alloc_context *data_ac,
-			struct ocfs2_alloc_context *meta_ac,
-			struct buffer_head **new_bh)
+static int ocfs2_do_extend_dir(struct super_block *sb,
+			       handle_t *handle,
+			       struct inode *dir,
+			       struct buffer_head *parent_fe_bh,
+			       struct ocfs2_alloc_context *data_ac,
+			       struct ocfs2_alloc_context *meta_ac,
+			       struct buffer_head **new_bh)
 {
 	int status;
 	int extend;
@@ -396,10 +1408,18 @@
 	return status;
 }
 
-/* assumes you already have a cluster lock on the directory. */
+/*
+ * Assumes you already have a cluster lock on the directory.
+ *
+ * 'blocks_wanted' is only used if we have an inline directory which
+ * is to be turned into an extent based one. The size of the dirent to
+ * insert might be larger than the space gained by growing to just one
+ * block, so we may have to grow the inode by two blocks in that case.
+ */
 static int ocfs2_extend_dir(struct ocfs2_super *osb,
 			    struct inode *dir,
 			    struct buffer_head *parent_fe_bh,
+			    unsigned int blocks_wanted,
 			    struct buffer_head **new_de_bh)
 {
 	int status = 0;
@@ -415,6 +1435,38 @@
 
 	mlog_entry_void();
 
+	if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+		status = ocfs2_expand_inline_dir(dir, parent_fe_bh,
+						 blocks_wanted, &new_bh);
+		if (status) {
+			mlog_errno(status);
+			goto bail;
+		}
+
+		if (blocks_wanted == 1) {
+			/*
+			 * If the new dirent will fit inside the space
+			 * created by pushing out to one block, then
+			 * we can complete the operation
+			 * here. Otherwise we have to expand i_size
+			 * and format the 2nd block below.
+			 */
+			BUG_ON(new_bh == NULL);
+			goto bail_bh;
+		}
+
+		/*
+		 * Get rid of 'new_bh' - we want to format the 2nd
+		 * data block and return that instead.
+		 */
+		brelse(new_bh);
+		new_bh = NULL;
+
+		dir_i_size = i_size_read(dir);
+		credits = OCFS2_SIMPLE_DIR_EXTEND_CREDITS;
+		goto do_extend;
+	}
+
 	dir_i_size = i_size_read(dir);
 	mlog(0, "extending dir %llu (i_size = %lld)\n",
 	     (unsigned long long)OCFS2_I(dir)->ip_blkno, dir_i_size);
@@ -452,6 +1504,7 @@
 		credits = OCFS2_SIMPLE_DIR_EXTEND_CREDITS;
 	}
 
+do_extend:
 	down_write(&OCFS2_I(dir)->ip_alloc_sem);
 	drop_alloc_sem = 1;
 
@@ -497,6 +1550,7 @@
 		goto bail;
 	}
 
+bail_bh:
 	*new_de_bh = new_bh;
 	get_bh(*new_de_bh);
 bail:
@@ -517,42 +1571,72 @@
 	return status;
 }
 
-/*
- * Search the dir for a good spot, extending it if necessary. The
- * block containing an appropriate record is returned in ret_de_bh.
- */
-int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb,
-				 struct inode *dir,
-				 struct buffer_head *parent_fe_bh,
-				 const char *name,
-				 int namelen,
-				 struct buffer_head **ret_de_bh)
+static int ocfs2_find_dir_space_id(struct inode *dir, struct buffer_head *di_bh,
+				   const char *name, int namelen,
+				   struct buffer_head **ret_de_bh,
+				   unsigned int *blocks_wanted)
+{
+	int ret;
+	struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+	struct ocfs2_dir_entry *de, *last_de = NULL;
+	char *de_buf, *limit;
+	unsigned long offset = 0;
+	unsigned int rec_len, new_rec_len;
+
+	de_buf = di->id2.i_data.id_data;
+	limit = de_buf + i_size_read(dir);
+	rec_len = OCFS2_DIR_REC_LEN(namelen);
+
+	while (de_buf < limit) {
+		de = (struct ocfs2_dir_entry *)de_buf;
+
+		if (!ocfs2_check_dir_entry(dir, de, di_bh, offset)) {
+			ret = -ENOENT;
+			goto out;
+		}
+		if (ocfs2_match(namelen, name, de)) {
+			ret = -EEXIST;
+			goto out;
+		}
+		if (ocfs2_dirent_would_fit(de, rec_len)) {
+			/* Ok, we found a spot. Return this bh and let
+			 * the caller actually fill it in. */
+			*ret_de_bh = di_bh;
+			get_bh(*ret_de_bh);
+			ret = 0;
+			goto out;
+		}
+
+		last_de = de;
+		de_buf += le16_to_cpu(de->rec_len);
+		offset += le16_to_cpu(de->rec_len);
+	}
+
+	/*
+	 * We're going to require expansion of the directory - figure
+	 * out how many blocks we'll need so that a place for the
+	 * dirent can be found.
+	 */
+	*blocks_wanted = 1;
+	new_rec_len = le16_to_cpu(last_de->rec_len) + (dir->i_sb->s_blocksize - i_size_read(dir));
+	if (new_rec_len < (rec_len + OCFS2_DIR_REC_LEN(last_de->name_len)))
+		*blocks_wanted = 2;
+
+	ret = -ENOSPC;
+out:
+	return ret;
+}
+
+static int ocfs2_find_dir_space_el(struct inode *dir, const char *name,
+				   int namelen, struct buffer_head **ret_de_bh)
 {
 	unsigned long offset;
-	struct buffer_head * bh = NULL;
+	struct buffer_head *bh = NULL;
 	unsigned short rec_len;
-	struct ocfs2_dinode *fe;
 	struct ocfs2_dir_entry *de;
-	struct super_block *sb;
+	struct super_block *sb = dir->i_sb;
 	int status;
 
-	mlog_entry_void();
-
-	mlog(0, "getting ready to insert namelen %d into dir %llu\n",
-	     namelen, (unsigned long long)OCFS2_I(dir)->ip_blkno);
-
-	BUG_ON(!S_ISDIR(dir->i_mode));
-	fe = (struct ocfs2_dinode *) parent_fe_bh->b_data;
-	BUG_ON(le64_to_cpu(fe->i_size) != i_size_read(dir));
-
-	sb = dir->i_sb;
-
-	if (!namelen) {
-		status = -EINVAL;
-		mlog_errno(status);
-		goto bail;
-	}
-
 	bh = ocfs2_bread(dir, 0, &status, 0);
 	if (!bh) {
 		mlog_errno(status);
@@ -568,17 +1652,11 @@
 			bh = NULL;
 
 			if (i_size_read(dir) <= offset) {
-				status = ocfs2_extend_dir(osb,
-							  dir,
-							  parent_fe_bh,
-							  &bh);
-				if (status < 0) {
-					mlog_errno(status);
-					goto bail;
-				}
-				BUG_ON(!bh);
-				*ret_de_bh = bh;
-				get_bh(*ret_de_bh);
+				/*
+				 * Caller will have to expand this
+				 * directory.
+				 */
+				status = -ENOSPC;
 				goto bail;
 			}
 			bh = ocfs2_bread(dir,
@@ -600,10 +1678,7 @@
 			status = -EEXIST;
 			goto bail;
 		}
-		if (((le64_to_cpu(de->inode) == 0) &&
-		     (le16_to_cpu(de->rec_len) >= rec_len)) ||
-		    (le16_to_cpu(de->rec_len) >=
-		     (OCFS2_DIR_REC_LEN(de->name_len) + rec_len))) {
+		if (ocfs2_dirent_would_fit(de, rec_len)) {
 			/* Ok, we found a spot. Return this bh and let
 			 * the caller actually fill it in. */
 			*ret_de_bh = bh;
@@ -623,3 +1698,61 @@
 	mlog_exit(status);
 	return status;
 }
+
+int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb,
+				 struct inode *dir,
+				 struct buffer_head *parent_fe_bh,
+				 const char *name,
+				 int namelen,
+				 struct buffer_head **ret_de_bh)
+{
+	int ret;
+	unsigned int blocks_wanted = 1;
+	struct buffer_head *bh = NULL;
+
+	mlog(0, "getting ready to insert namelen %d into dir %llu\n",
+	     namelen, (unsigned long long)OCFS2_I(dir)->ip_blkno);
+
+	*ret_de_bh = NULL;
+
+	if (!namelen) {
+		ret = -EINVAL;
+		mlog_errno(ret);
+		goto out;
+	}
+
+	if (OCFS2_I(dir)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+		ret = ocfs2_find_dir_space_id(dir, parent_fe_bh, name,
+					      namelen, &bh, &blocks_wanted);
+	} else
+		ret = ocfs2_find_dir_space_el(dir, name, namelen, &bh);
+
+	if (ret && ret != -ENOSPC) {
+		mlog_errno(ret);
+		goto out;
+	}
+
+	if (ret == -ENOSPC) {
+		/*
+		 * We have to expand the directory to add this name.
+		 */
+		BUG_ON(bh);
+
+		ret = ocfs2_extend_dir(osb, dir, parent_fe_bh, blocks_wanted,
+				       &bh);
+		if (ret) {
+			if (ret != -ENOSPC)
+				mlog_errno(ret);
+			goto out;
+		}
+
+		BUG_ON(!bh);
+	}
+
+	*ret_de_bh = bh;
+	bh = NULL;
+out:
+	if (bh)
+		brelse(bh);
+	return ret;
+}
diff --git a/fs/ocfs2/dir.h b/fs/ocfs2/dir.h
index 3f67e14..ce48b90 100644
--- a/fs/ocfs2/dir.h
+++ b/fs/ocfs2/dir.h
@@ -26,17 +26,49 @@
 #ifndef OCFS2_DIR_H
 #define OCFS2_DIR_H
 
+struct buffer_head *ocfs2_find_entry(const char *name,
+				     int namelen,
+				     struct inode *dir,
+				     struct ocfs2_dir_entry **res_dir);
+int ocfs2_delete_entry(handle_t *handle,
+		       struct inode *dir,
+		       struct ocfs2_dir_entry *de_del,
+		       struct buffer_head *bh);
+int __ocfs2_add_entry(handle_t *handle,
+		      struct inode *dir,
+		      const char *name, int namelen,
+		      struct inode *inode, u64 blkno,
+		      struct buffer_head *parent_fe_bh,
+		      struct buffer_head *insert_bh);
+static inline int ocfs2_add_entry(handle_t *handle,
+				  struct dentry *dentry,
+				  struct inode *inode, u64 blkno,
+				  struct buffer_head *parent_fe_bh,
+				  struct buffer_head *insert_bh)
+{
+	return __ocfs2_add_entry(handle, dentry->d_parent->d_inode,
+				 dentry->d_name.name, dentry->d_name.len,
+				 inode, blkno, parent_fe_bh, insert_bh);
+}
+int ocfs2_update_entry(struct inode *dir, handle_t *handle,
+		       struct buffer_head *de_bh, struct ocfs2_dir_entry *de,
+		       struct inode *new_entry_inode);
+
 int ocfs2_check_dir_for_entry(struct inode *dir,
 			      const char *name,
 			      int namelen);
-int ocfs2_empty_dir(struct inode *inode);  /* FIXME: to namei.c */
+int ocfs2_empty_dir(struct inode *inode);
 int ocfs2_find_files_on_disk(const char *name,
 			     int namelen,
 			     u64 *blkno,
 			     struct inode *inode,
 			     struct buffer_head **dirent_bh,
 			     struct ocfs2_dir_entry **dirent);
+int ocfs2_lookup_ino_from_name(struct inode *dir, const char *name,
+			       int namelen, u64 *blkno);
 int ocfs2_readdir(struct file *filp, void *dirent, filldir_t filldir);
+int ocfs2_dir_foreach(struct inode *inode, loff_t *f_pos, void *priv,
+		      filldir_t filldir);
 int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb,
 				 struct inode *dir,
 				 struct buffer_head *parent_fe_bh,
@@ -44,11 +76,11 @@
 				 int namelen,
 				 struct buffer_head **ret_de_bh);
 struct ocfs2_alloc_context;
-int ocfs2_do_extend_dir(struct super_block *sb,
-			handle_t *handle,
-			struct inode *dir,
-			struct buffer_head *parent_fe_bh,
-			struct ocfs2_alloc_context *data_ac,
-			struct ocfs2_alloc_context *meta_ac,
-			struct buffer_head **new_bh);
+int ocfs2_fill_new_dir(struct ocfs2_super *osb,
+		       handle_t *handle,
+		       struct inode *parent,
+		       struct inode *inode,
+		       struct buffer_head *fe_bh,
+		       struct ocfs2_alloc_context *data_ac);
+
 #endif /* OCFS2_DIR_H */
diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c
index f71250e..41c76ff 100644
--- a/fs/ocfs2/dlmglue.c
+++ b/fs/ocfs2/dlmglue.c
@@ -1482,6 +1482,7 @@
 	lvb->lvb_imtime_packed =
 		cpu_to_be64(ocfs2_pack_timespec(&inode->i_mtime));
 	lvb->lvb_iattr    = cpu_to_be32(oi->ip_attr);
+	lvb->lvb_idynfeatures = cpu_to_be16(oi->ip_dyn_features);
 	lvb->lvb_igeneration = cpu_to_be32(inode->i_generation);
 
 out:
@@ -1515,6 +1516,7 @@
 	i_size_write(inode, be64_to_cpu(lvb->lvb_isize));
 
 	oi->ip_attr = be32_to_cpu(lvb->lvb_iattr);
+	oi->ip_dyn_features = be16_to_cpu(lvb->lvb_idynfeatures);
 	ocfs2_set_inode_flags(inode);
 
 	/* fast-symlinks are a special case */
diff --git a/fs/ocfs2/dlmglue.h b/fs/ocfs2/dlmglue.h
index 492bad3..87a785e 100644
--- a/fs/ocfs2/dlmglue.h
+++ b/fs/ocfs2/dlmglue.h
@@ -29,12 +29,12 @@
 
 #include "dcache.h"
 
-#define OCFS2_LVB_VERSION 4
+#define OCFS2_LVB_VERSION 5
 
 struct ocfs2_meta_lvb {
 	__u8         lvb_version;
 	__u8         lvb_reserved0;
-	__be16       lvb_reserved1;
+	__be16       lvb_idynfeatures;
 	__be32       lvb_iclusters;
 	__be32       lvb_iuid;
 	__be32       lvb_igid;
diff --git a/fs/ocfs2/export.c b/fs/ocfs2/export.c
index bc48177..c3bbc19 100644
--- a/fs/ocfs2/export.c
+++ b/fs/ocfs2/export.c
@@ -88,8 +88,6 @@
 	struct dentry *parent;
 	struct inode *inode;
 	struct inode *dir = child->d_inode;
-	struct buffer_head *dirent_bh = NULL;
-	struct ocfs2_dir_entry *dirent;
 
 	mlog_entry("(0x%p, '%.*s')\n", child,
 		   child->d_name.len, child->d_name.name);
@@ -105,8 +103,7 @@
 		goto bail;
 	}
 
-	status = ocfs2_find_files_on_disk("..", 2, &blkno, dir, &dirent_bh,
-					  &dirent);
+	status = ocfs2_lookup_ino_from_name(dir, "..", 2, &blkno);
 	if (status < 0) {
 		parent = ERR_PTR(-ENOENT);
 		goto bail_unlock;
@@ -131,9 +128,6 @@
 bail_unlock:
 	ocfs2_meta_unlock(dir, 0);
 
-	if (dirent_bh)
-		brelse(dirent_bh);
-
 bail:
 	mlog_exit_ptr(parent);
 
diff --git a/fs/ocfs2/extent_map.c b/fs/ocfs2/extent_map.c
index 03c1d365..c58668a 100644
--- a/fs/ocfs2/extent_map.c
+++ b/fs/ocfs2/extent_map.c
@@ -387,6 +387,12 @@
 	struct ocfs2_extent_rec *rec;
 	u32 coff;
 
+	if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+		ret = -ERANGE;
+		mlog_errno(ret);
+		goto out;
+	}
+
 	ret = ocfs2_extent_map_lookup(inode, v_cluster, p_cluster,
 				      num_clusters, extent_flags);
 	if (ret == 0)
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index f3bc365..a62b14e 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -397,6 +397,15 @@
 	unmap_mapping_range(inode->i_mapping, new_i_size + PAGE_SIZE - 1, 0, 1);
 	truncate_inode_pages(inode->i_mapping, new_i_size);
 
+	if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+		status = ocfs2_truncate_inline(inode, di_bh, new_i_size,
+					       i_size_read(inode), 0);
+		if (status)
+			mlog_errno(status);
+
+		goto bail_unlock_data;
+	}
+
 	/* alright, we're going to need to do a full blown alloc size
 	 * change. Orphan the inode so that recovery can complete the
 	 * truncate if necessary. This does the task of marking
@@ -779,25 +788,6 @@
 	return status;
 }
 
-static int ocfs2_extend_allocation(struct inode *inode, u32 logical_start,
-				   u32 clusters_to_add, int mark_unwritten)
-{
-	int ret;
-
-	/*
-	 * The alloc sem blocks peope in read/write from reading our
-	 * allocation until we're done changing it. We depend on
-	 * i_mutex to block other extend/truncate calls while we're
-	 * here.
-	 */
-	down_write(&OCFS2_I(inode)->ip_alloc_sem);
-	ret = __ocfs2_extend_allocation(inode, logical_start, clusters_to_add,
-					mark_unwritten);
-	up_write(&OCFS2_I(inode)->ip_alloc_sem);
-
-	return ret;
-}
-
 /* Some parts of this taken from generic_cont_expand, which turned out
  * to be too fragile to do exactly what we need without us having to
  * worry about recursive locking in ->prepare_write() and
@@ -889,25 +879,48 @@
 	return ret;
 }
 
-/* 
- * A tail_to_skip value > 0 indicates that we're being called from
- * ocfs2_file_aio_write(). This has the following implications:
- *
- * - we don't want to update i_size
- * - di_bh will be NULL, which is fine because it's only used in the
- *   case where we want to update i_size.
- * - ocfs2_zero_extend() will then only be filling the hole created
- *   between i_size and the start of the write.
- */
+int ocfs2_extend_no_holes(struct inode *inode, u64 new_i_size, u64 zero_to)
+{
+	int ret;
+	u32 clusters_to_add;
+	struct ocfs2_inode_info *oi = OCFS2_I(inode);
+
+	clusters_to_add = ocfs2_clusters_for_bytes(inode->i_sb, new_i_size);
+	if (clusters_to_add < oi->ip_clusters)
+		clusters_to_add = 0;
+	else
+		clusters_to_add -= oi->ip_clusters;
+
+	if (clusters_to_add) {
+		ret = __ocfs2_extend_allocation(inode, oi->ip_clusters,
+						clusters_to_add, 0);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+	}
+
+	/*
+	 * Call this even if we don't add any clusters to the tree. We
+	 * still need to zero the area between the old i_size and the
+	 * new i_size.
+	 */
+	ret = ocfs2_zero_extend(inode, zero_to);
+	if (ret < 0)
+		mlog_errno(ret);
+
+out:
+	return ret;
+}
+
 static int ocfs2_extend_file(struct inode *inode,
 			     struct buffer_head *di_bh,
-			     u64 new_i_size,
-			     size_t tail_to_skip)
+			     u64 new_i_size)
 {
-	int ret = 0;
-	u32 clusters_to_add = 0;
+	int ret = 0, data_locked = 0;
+	struct ocfs2_inode_info *oi = OCFS2_I(inode);
 
-	BUG_ON(!tail_to_skip && !di_bh);
+	BUG_ON(!di_bh);
 
 	/* setattr sometimes calls us like this. */
 	if (new_i_size == 0)
@@ -917,13 +930,18 @@
   		goto out;
 	BUG_ON(new_i_size < i_size_read(inode));
 
-	if (ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) {
-		BUG_ON(tail_to_skip != 0);
+	/*
+	 * Fall through for converting inline data, even if the fs
+	 * supports sparse files.
+	 *
+	 * The check for inline data here is legal - nobody can add
+	 * the feature since we have i_mutex. We must check it again
+	 * after acquiring ip_alloc_sem though, as paths like mmap
+	 * might have raced us to converting the inode to extents.
+	 */
+	if (!(oi->ip_dyn_features & OCFS2_INLINE_DATA_FL)
+	    && ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)))
 		goto out_update_size;
-	}
-
-	clusters_to_add = ocfs2_clusters_for_bytes(inode->i_sb, new_i_size) - 
-		OCFS2_I(inode)->ip_clusters;
 
 	/* 
 	 * protect the pages that ocfs2_zero_extend is going to be
@@ -937,39 +955,52 @@
 		mlog_errno(ret);
 		goto out;
 	}
+	data_locked = 1;
 
-	if (clusters_to_add) {
-		ret = ocfs2_extend_allocation(inode,
-					      OCFS2_I(inode)->ip_clusters,
-					      clusters_to_add, 0);
-		if (ret < 0) {
+	/*
+	 * The alloc sem blocks people in read/write from reading our
+	 * allocation until we're done changing it. We depend on
+	 * i_mutex to block other extend/truncate calls while we're
+	 * here.
+	 */
+	down_write(&oi->ip_alloc_sem);
+
+	if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+		/*
+		 * We can optimize small extends by keeping the inodes
+		 * inline data.
+		 */
+		if (ocfs2_size_fits_inline_data(di_bh, new_i_size)) {
+			up_write(&oi->ip_alloc_sem);
+			goto out_update_size;
+		}
+
+		ret = ocfs2_convert_inline_data_to_extents(inode, di_bh);
+		if (ret) {
+			up_write(&oi->ip_alloc_sem);
+
 			mlog_errno(ret);
 			goto out_unlock;
 		}
 	}
 
-	/*
-	 * Call this even if we don't add any clusters to the tree. We
-	 * still need to zero the area between the old i_size and the
-	 * new i_size.
-	 */
-	ret = ocfs2_zero_extend(inode, (u64)new_i_size - tail_to_skip);
+	if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)))
+		ret = ocfs2_extend_no_holes(inode, new_i_size, new_i_size);
+
+	up_write(&oi->ip_alloc_sem);
+
 	if (ret < 0) {
 		mlog_errno(ret);
 		goto out_unlock;
 	}
 
 out_update_size:
-	if (!tail_to_skip) {
-		/* We're being called from ocfs2_setattr() which wants
-		 * us to update i_size */
-		ret = ocfs2_simple_size_update(inode, di_bh, new_i_size);
-		if (ret < 0)
-			mlog_errno(ret);
-	}
+	ret = ocfs2_simple_size_update(inode, di_bh, new_i_size);
+	if (ret < 0)
+		mlog_errno(ret);
 
 out_unlock:
-	if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)))
+	if (data_locked)
 		ocfs2_data_unlock(inode, 1);
 
 out:
@@ -1035,7 +1066,7 @@
 		if (i_size_read(inode) > attr->ia_size)
 			status = ocfs2_truncate_file(inode, bh, attr->ia_size);
 		else
-			status = ocfs2_extend_file(inode, bh, attr->ia_size, 0);
+			status = ocfs2_extend_file(inode, bh, attr->ia_size);
 		if (status < 0) {
 			if (status != -ENOSPC)
 				mlog_errno(status);
@@ -1243,6 +1274,31 @@
 {
 	int ret;
 	u32 cpos, phys_cpos, clusters, alloc_size;
+	u64 end = start + len;
+	struct buffer_head *di_bh = NULL;
+
+	if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+		ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
+				       OCFS2_I(inode)->ip_blkno, &di_bh,
+				       OCFS2_BH_CACHED, inode);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+
+		/*
+		 * Nothing to do if the requested reservation range
+		 * fits within the inode.
+		 */
+		if (ocfs2_size_fits_inline_data(di_bh, end))
+			goto out;
+
+		ret = ocfs2_convert_inline_data_to_extents(inode, di_bh);
+		if (ret) {
+			mlog_errno(ret);
+			goto out;
+		}
+	}
 
 	/*
 	 * We consider both start and len to be inclusive.
@@ -1288,6 +1344,8 @@
 
 	ret = 0;
 out:
+
+	brelse(di_bh);
 	return ret;
 }
 
@@ -1469,6 +1527,14 @@
 	if (byte_len == 0)
 		return 0;
 
+	if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+		ret = ocfs2_truncate_inline(inode, di_bh, byte_start,
+					    byte_start + byte_len, 1);
+		if (ret)
+			mlog_errno(ret);
+		return ret;
+	}
+
 	trunc_start = ocfs2_clusters_for_bytes(osb->sb, byte_start);
 	trunc_len = (byte_start + byte_len) >> osb->s_clustersize_bits;
 	if (trunc_len >= trunc_start)
@@ -1713,15 +1779,13 @@
 					 int appending,
 					 int *direct_io)
 {
-	int ret = 0, meta_level = appending;
+	int ret = 0, meta_level = 0;
 	struct inode *inode = dentry->d_inode;
-	u32 clusters;
-	loff_t newsize, saved_pos;
+	loff_t saved_pos, end;
 
 	/* 
-	 * We sample i_size under a read level meta lock to see if our write
-	 * is extending the file, if it is we back off and get a write level
-	 * meta lock.
+	 * We start with a read level meta lock and only jump to an ex
+	 * if we need to make modifications here.
 	 */
 	for(;;) {
 		ret = ocfs2_meta_lock(inode, NULL, meta_level);
@@ -1763,87 +1827,47 @@
 			saved_pos = *ppos;
 		}
 
-		if (ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) {
-			loff_t end = saved_pos + count;
+		end = saved_pos + count;
 
-			/*
-			 * Skip the O_DIRECT checks if we don't need
-			 * them.
-			 */
-			if (!direct_io || !(*direct_io))
-				break;
+		/*
+		 * Skip the O_DIRECT checks if we don't need
+		 * them.
+		 */
+		if (!direct_io || !(*direct_io))
+			break;
 
-			/*
-			 * Allowing concurrent direct writes means
-			 * i_size changes wouldn't be synchronized, so
-			 * one node could wind up truncating another
-			 * nodes writes.
-			 */
-			if (end > i_size_read(inode)) {
-				*direct_io = 0;
-				break;
-			}
-
-			/*
-			 * We don't fill holes during direct io, so
-			 * check for them here. If any are found, the
-			 * caller will have to retake some cluster
-			 * locks and initiate the io as buffered.
-			 */
-			ret = ocfs2_check_range_for_holes(inode, saved_pos,
-							  count);
-			if (ret == 1) {
-				*direct_io = 0;
-				ret = 0;
-			} else if (ret < 0)
-				mlog_errno(ret);
+		/*
+		 * There's no sane way to do direct writes to an inode
+		 * with inline data.
+		 */
+		if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+			*direct_io = 0;
 			break;
 		}
 
 		/*
-		 * The rest of this loop is concerned with legacy file
-		 * systems which don't support sparse files.
+		 * Allowing concurrent direct writes means
+		 * i_size changes wouldn't be synchronized, so
+		 * one node could wind up truncating another
+		 * nodes writes.
 		 */
-
-		newsize = count + saved_pos;
-
-		mlog(0, "pos=%lld newsize=%lld cursize=%lld\n",
-		     (long long) saved_pos, (long long) newsize,
-		     (long long) i_size_read(inode));
-
-		/* No need for a higher level metadata lock if we're
-		 * never going past i_size. */
-		if (newsize <= i_size_read(inode))
+		if (end > i_size_read(inode)) {
+			*direct_io = 0;
 			break;
-
-		if (meta_level == 0) {
-			ocfs2_meta_unlock(inode, meta_level);
-			meta_level = 1;
-			continue;
 		}
 
-		spin_lock(&OCFS2_I(inode)->ip_lock);
-		clusters = ocfs2_clusters_for_bytes(inode->i_sb, newsize) -
-			OCFS2_I(inode)->ip_clusters;
-		spin_unlock(&OCFS2_I(inode)->ip_lock);
-
-		mlog(0, "Writing at EOF, may need more allocation: "
-		     "i_size = %lld, newsize = %lld, need %u clusters\n",
-		     (long long) i_size_read(inode), (long long) newsize,
-		     clusters);
-
-		/* We only want to continue the rest of this loop if
-		 * our extend will actually require more
-		 * allocation. */
-		if (!clusters)
-			break;
-
-		ret = ocfs2_extend_file(inode, NULL, newsize, count);
-		if (ret < 0) {
-			if (ret != -ENOSPC)
-				mlog_errno(ret);
-			goto out_unlock;
-		}
+		/*
+		 * We don't fill holes during direct io, so
+		 * check for them here. If any are found, the
+		 * caller will have to retake some cluster
+		 * locks and initiate the io as buffered.
+		 */
+		ret = ocfs2_check_range_for_holes(inode, saved_pos, count);
+		if (ret == 1) {
+			*direct_io = 0;
+			ret = 0;
+		} else if (ret < 0)
+			mlog_errno(ret);
 		break;
 	}
 
diff --git a/fs/ocfs2/file.h b/fs/ocfs2/file.h
index 36fe27f..066f14a 100644
--- a/fs/ocfs2/file.h
+++ b/fs/ocfs2/file.h
@@ -47,6 +47,8 @@
 			       struct ocfs2_alloc_context *data_ac,
 			       struct ocfs2_alloc_context *meta_ac,
 			       enum ocfs2_alloc_restarted *reason_ret);
+int ocfs2_extend_no_holes(struct inode *inode, u64 new_i_size,
+			  u64 zero_to);
 int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_dinode *di,
 			  u32 clusters_to_add, u32 extents_to_split,
 			  struct ocfs2_alloc_context **data_ac,
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
index c53a676..1d5e0cb 100644
--- a/fs/ocfs2/inode.c
+++ b/fs/ocfs2/inode.c
@@ -241,6 +241,7 @@
 
 	OCFS2_I(inode)->ip_clusters = le32_to_cpu(fe->i_clusters);
 	OCFS2_I(inode)->ip_attr = le32_to_cpu(fe->i_attr);
+	OCFS2_I(inode)->ip_dyn_features = le16_to_cpu(fe->i_dyn_features);
 
 	inode->i_version = 1;
 	inode->i_generation = le32_to_cpu(fe->i_generation);
@@ -513,6 +514,10 @@
 
 	fe = (struct ocfs2_dinode *) fe_bh->b_data;
 
+	/*
+	 * This check will also skip truncate of inodes with inline
+	 * data and fast symlinks.
+	 */
 	if (fe->i_clusters) {
 		handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
 		if (IS_ERR(handle)) {
@@ -1220,6 +1225,7 @@
 	fe->i_clusters = cpu_to_le32(OCFS2_I(inode)->ip_clusters);
 	ocfs2_get_inode_flags(OCFS2_I(inode));
 	fe->i_attr = cpu_to_le32(OCFS2_I(inode)->ip_attr);
+	fe->i_dyn_features = cpu_to_le16(OCFS2_I(inode)->ip_dyn_features);
 	spin_unlock(&OCFS2_I(inode)->ip_lock);
 
 	fe->i_size = cpu_to_le64(i_size_read(inode));
@@ -1257,6 +1263,7 @@
 
 	OCFS2_I(inode)->ip_clusters = le32_to_cpu(fe->i_clusters);
 	OCFS2_I(inode)->ip_attr = le32_to_cpu(fe->i_attr);
+	OCFS2_I(inode)->ip_dyn_features = le16_to_cpu(fe->i_dyn_features);
 	ocfs2_set_inode_flags(inode);
 	i_size_write(inode, le64_to_cpu(fe->i_size));
 	inode->i_nlink = le16_to_cpu(fe->i_links_count);
diff --git a/fs/ocfs2/inode.h b/fs/ocfs2/inode.h
index a41d081..70e881c 100644
--- a/fs/ocfs2/inode.h
+++ b/fs/ocfs2/inode.h
@@ -51,6 +51,7 @@
 
 	u32				ip_flags; /* see below */
 	u32				ip_attr; /* inode attributes */
+	u16				ip_dyn_features;
 
 	/* protected by recovery_lock. */
 	struct inode			*ip_next_orphan;
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c
index dbfb20b..f9d01e2 100644
--- a/fs/ocfs2/journal.c
+++ b/fs/ocfs2/journal.c
@@ -35,13 +35,13 @@
 #include "ocfs2.h"
 
 #include "alloc.h"
+#include "dir.h"
 #include "dlmglue.h"
 #include "extent_map.h"
 #include "heartbeat.h"
 #include "inode.h"
 #include "journal.h"
 #include "localalloc.h"
-#include "namei.h"
 #include "slot_map.h"
 #include "super.h"
 #include "vote.h"
@@ -1213,17 +1213,49 @@
 	return status;
 }
 
+struct ocfs2_orphan_filldir_priv {
+	struct inode		*head;
+	struct ocfs2_super	*osb;
+};
+
+static int ocfs2_orphan_filldir(void *priv, const char *name, int name_len,
+				loff_t pos, u64 ino, unsigned type)
+{
+	struct ocfs2_orphan_filldir_priv *p = priv;
+	struct inode *iter;
+
+	if (name_len == 1 && !strncmp(".", name, 1))
+		return 0;
+	if (name_len == 2 && !strncmp("..", name, 2))
+		return 0;
+
+	/* Skip bad inodes so that recovery can continue */
+	iter = ocfs2_iget(p->osb, ino,
+			  OCFS2_FI_FLAG_ORPHAN_RECOVERY);
+	if (IS_ERR(iter))
+		return 0;
+
+	mlog(0, "queue orphan %llu\n",
+	     (unsigned long long)OCFS2_I(iter)->ip_blkno);
+	/* No locking is required for the next_orphan queue as there
+	 * is only ever a single process doing orphan recovery. */
+	OCFS2_I(iter)->ip_next_orphan = p->head;
+	p->head = iter;
+
+	return 0;
+}
+
 static int ocfs2_queue_orphans(struct ocfs2_super *osb,
 			       int slot,
 			       struct inode **head)
 {
 	int status;
 	struct inode *orphan_dir_inode = NULL;
-	struct inode *iter;
-	unsigned long offset, blk, local;
-	struct buffer_head *bh = NULL;
-	struct ocfs2_dir_entry *de;
-	struct super_block *sb = osb->sb;
+	struct ocfs2_orphan_filldir_priv priv;
+	loff_t pos = 0;
+
+	priv.osb = osb;
+	priv.head = *head;
 
 	orphan_dir_inode = ocfs2_get_system_file_inode(osb,
 						       ORPHAN_DIR_SYSTEM_INODE,
@@ -1241,77 +1273,15 @@
 		goto out;
 	}
 
-	offset = 0;
-	iter = NULL;
-	while(offset < i_size_read(orphan_dir_inode)) {
-		blk = offset >> sb->s_blocksize_bits;
-
-		bh = ocfs2_bread(orphan_dir_inode, blk, &status, 0);
-		if (!bh)
-			status = -EINVAL;
-		if (status < 0) {
-			if (bh)
-				brelse(bh);
-			mlog_errno(status);
-			goto out_unlock;
-		}
-
-		local = 0;
-		while(offset < i_size_read(orphan_dir_inode)
-		      && local < sb->s_blocksize) {
-			de = (struct ocfs2_dir_entry *) (bh->b_data + local);
-
-			if (!ocfs2_check_dir_entry(orphan_dir_inode,
-						  de, bh, local)) {
-				status = -EINVAL;
-				mlog_errno(status);
-				brelse(bh);
-				goto out_unlock;
-			}
-
-			local += le16_to_cpu(de->rec_len);
-			offset += le16_to_cpu(de->rec_len);
-
-			/* I guess we silently fail on no inode? */
-			if (!le64_to_cpu(de->inode))
-				continue;
-			if (de->file_type > OCFS2_FT_MAX) {
-				mlog(ML_ERROR,
-				     "block %llu contains invalid de: "
-				     "inode = %llu, rec_len = %u, "
-				     "name_len = %u, file_type = %u, "
-				     "name='%.*s'\n",
-				     (unsigned long long)bh->b_blocknr,
-				     (unsigned long long)le64_to_cpu(de->inode),
-				     le16_to_cpu(de->rec_len),
-				     de->name_len,
-				     de->file_type,
-				     de->name_len,
-				     de->name);
-				continue;
-			}
-			if (de->name_len == 1 && !strncmp(".", de->name, 1))
-				continue;
-			if (de->name_len == 2 && !strncmp("..", de->name, 2))
-				continue;
-
-			iter = ocfs2_iget(osb, le64_to_cpu(de->inode),
-					  OCFS2_FI_FLAG_ORPHAN_RECOVERY);
-			if (IS_ERR(iter))
-				continue;
-
-			mlog(0, "queue orphan %llu\n",
-			     (unsigned long long)OCFS2_I(iter)->ip_blkno);
-			/* No locking is required for the next_orphan
-			 * queue as there is only ever a single
-			 * process doing orphan recovery. */
-			OCFS2_I(iter)->ip_next_orphan = *head;
-			*head = iter;
-		}
-		brelse(bh);
+	status = ocfs2_dir_foreach(orphan_dir_inode, &pos, &priv,
+				   ocfs2_orphan_filldir);
+	if (status) {
+		mlog_errno(status);
+		goto out;
 	}
 
-out_unlock:
+	*head = priv.head;
+
 	ocfs2_meta_unlock(orphan_dir_inode, 0);
 out:
 	mutex_unlock(&orphan_dir_inode->i_mutex);
diff --git a/fs/ocfs2/journal.h b/fs/ocfs2/journal.h
index ce60aab..4b32e09 100644
--- a/fs/ocfs2/journal.h
+++ b/fs/ocfs2/journal.h
@@ -282,6 +282,9 @@
  * prev. group desc. if we relink. */
 #define OCFS2_SUBALLOC_ALLOC (3)
 
+#define OCFS2_INLINE_TO_EXTENTS_CREDITS (OCFS2_SUBALLOC_ALLOC		\
+					 + OCFS2_INODE_UPDATE_CREDITS)
+
 /* dinode + group descriptor update. We don't relink on free yet. */
 #define OCFS2_SUBALLOC_FREE  (2)
 
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
index 701e6d0..7292590 100644
--- a/fs/ocfs2/namei.c
+++ b/fs/ocfs2/namei.c
@@ -64,29 +64,6 @@
 
 #include "buffer_head_io.h"
 
-#define NAMEI_RA_CHUNKS  2
-#define NAMEI_RA_BLOCKS  4
-#define NAMEI_RA_SIZE        (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS)
-#define NAMEI_RA_INDEX(c,b)  (((c) * NAMEI_RA_BLOCKS) + (b))
-
-static int inline ocfs2_search_dirblock(struct buffer_head *bh,
-					struct inode *dir,
-					const char *name, int namelen,
-					unsigned long offset,
-					struct ocfs2_dir_entry **res_dir);
-
-static int ocfs2_delete_entry(handle_t *handle,
-			      struct inode *dir,
-			      struct ocfs2_dir_entry *de_del,
-			      struct buffer_head *bh);
-
-static int __ocfs2_add_entry(handle_t *handle,
-			     struct inode *dir,
-			     const char *name, int namelen,
-			     struct inode *inode, u64 blkno,
-			     struct buffer_head *parent_fe_bh,
-			     struct buffer_head *insert_bh);
-
 static int ocfs2_mknod_locked(struct ocfs2_super *osb,
 			      struct inode *dir,
 			      struct dentry *dentry, int mode,
@@ -97,13 +74,6 @@
 			      struct inode **ret_inode,
 			      struct ocfs2_alloc_context *inode_ac);
 
-static int ocfs2_fill_new_dir(struct ocfs2_super *osb,
-			      handle_t *handle,
-			      struct inode *parent,
-			      struct inode *inode,
-			      struct buffer_head *fe_bh,
-			      struct ocfs2_alloc_context *data_ac);
-
 static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb,
 				    struct inode **ret_orphan_dir,
 				    struct inode *inode,
@@ -123,17 +93,6 @@
 				     struct inode *inode,
 				     const char *symname);
 
-static inline int ocfs2_add_entry(handle_t *handle,
-				  struct dentry *dentry,
-				  struct inode *inode, u64 blkno,
-				  struct buffer_head *parent_fe_bh,
-				  struct buffer_head *insert_bh)
-{
-	return __ocfs2_add_entry(handle, dentry->d_parent->d_inode,
-				 dentry->d_name.name, dentry->d_name.len,
-				 inode, blkno, parent_fe_bh, insert_bh);
-}
-
 /* An orphan dir name is an 8 byte value, printed as a hex string */
 #define OCFS2_ORPHAN_NAMELEN ((int)(2 * sizeof(u64)))
 
@@ -142,10 +101,8 @@
 {
 	int status;
 	u64 blkno;
-	struct buffer_head *dirent_bh = NULL;
 	struct inode *inode = NULL;
 	struct dentry *ret;
-	struct ocfs2_dir_entry *dirent;
 	struct ocfs2_inode_info *oi;
 
 	mlog_entry("(0x%p, 0x%p, '%.*s')\n", dir, dentry,
@@ -167,9 +124,8 @@
 		goto bail;
 	}
 
-	status = ocfs2_find_files_on_disk(dentry->d_name.name,
-					  dentry->d_name.len, &blkno,
-					  dir, &dirent_bh, &dirent);
+	status = ocfs2_lookup_ino_from_name(dir, dentry->d_name.name,
+					    dentry->d_name.len, &blkno);
 	if (status < 0)
 		goto bail_add;
 
@@ -224,83 +180,12 @@
 	ocfs2_meta_unlock(dir, 0);
 
 bail:
-	if (dirent_bh)
-		brelse(dirent_bh);
 
 	mlog_exit_ptr(ret);
 
 	return ret;
 }
 
-static int ocfs2_fill_new_dir(struct ocfs2_super *osb,
-			      handle_t *handle,
-			      struct inode *parent,
-			      struct inode *inode,
-			      struct buffer_head *fe_bh,
-			      struct ocfs2_alloc_context *data_ac)
-{
-	int status;
-	struct buffer_head *new_bh = NULL;
-	struct ocfs2_dir_entry *de = NULL;
-
-	mlog_entry_void();
-
-	status = ocfs2_do_extend_dir(osb->sb, handle, inode, fe_bh,
-				     data_ac, NULL, &new_bh);
-	if (status < 0) {
-		mlog_errno(status);
-		goto bail;
-	}
-
-	ocfs2_set_new_buffer_uptodate(inode, new_bh);
-
-	status = ocfs2_journal_access(handle, inode, new_bh,
-				      OCFS2_JOURNAL_ACCESS_CREATE);
-	if (status < 0) {
-		mlog_errno(status);
-		goto bail;
-	}
-	memset(new_bh->b_data, 0, osb->sb->s_blocksize);
-
-	de = (struct ocfs2_dir_entry *) new_bh->b_data;
-	de->inode = cpu_to_le64(OCFS2_I(inode)->ip_blkno);
-	de->name_len = 1;
-	de->rec_len =
-		cpu_to_le16(OCFS2_DIR_REC_LEN(de->name_len));
-	strcpy(de->name, ".");
-	ocfs2_set_de_type(de, S_IFDIR);
-	de = (struct ocfs2_dir_entry *) ((char *)de + le16_to_cpu(de->rec_len));
-	de->inode = cpu_to_le64(OCFS2_I(parent)->ip_blkno);
-	de->rec_len = cpu_to_le16(inode->i_sb->s_blocksize -
-				  OCFS2_DIR_REC_LEN(1));
-	de->name_len = 2;
-	strcpy(de->name, "..");
-	ocfs2_set_de_type(de, S_IFDIR);
-
-	status = ocfs2_journal_dirty(handle, new_bh);
-	if (status < 0) {
-		mlog_errno(status);
-		goto bail;
-	}
-
-	i_size_write(inode, inode->i_sb->s_blocksize);
-	inode->i_nlink = 2;
-	inode->i_blocks = ocfs2_inode_sector_count(inode);
-	status = ocfs2_mark_inode_dirty(handle, inode, fe_bh);
-	if (status < 0) {
-		mlog_errno(status);
-		goto bail;
-	}
-
-	status = 0;
-bail:
-	if (new_bh)
-		brelse(new_bh);
-
-	mlog_exit(status);
-	return status;
-}
-
 static int ocfs2_mknod(struct inode *dir,
 		       struct dentry *dentry,
 		       int mode,
@@ -365,9 +250,8 @@
 		goto leave;
 	}
 
-	/* are we making a directory? If so, reserve a cluster for his
-	 * 1st extent. */
-	if (S_ISDIR(mode)) {
+	/* Reserve a cluster if creating an extent based directory. */
+	if (S_ISDIR(mode) && !ocfs2_supports_inline_data(osb)) {
 		status = ocfs2_reserve_clusters(osb, 1, &data_ac);
 		if (status < 0) {
 			if (status != -ENOSPC)
@@ -564,10 +448,21 @@
 		cpu_to_le32(CURRENT_TIME.tv_nsec);
 	fe->i_dtime = 0;
 
-	fel = &fe->id2.i_list;
-	fel->l_tree_depth = 0;
-	fel->l_next_free_rec = 0;
-	fel->l_count = cpu_to_le16(ocfs2_extent_recs_per_inode(osb->sb));
+	/*
+	 * If supported, directories start with inline data.
+	 */
+	if (S_ISDIR(mode) && ocfs2_supports_inline_data(osb)) {
+		u16 feat = le16_to_cpu(fe->i_dyn_features);
+
+		fe->i_dyn_features = cpu_to_le16(feat | OCFS2_INLINE_DATA_FL);
+
+		fe->id2.i_data.id_count = cpu_to_le16(ocfs2_max_inline_data(osb->sb));
+	} else {
+		fel = &fe->id2.i_list;
+		fel->l_tree_depth = 0;
+		fel->l_next_free_rec = 0;
+		fel->l_count = cpu_to_le16(ocfs2_extent_recs_per_inode(osb->sb));
+	}
 
 	status = ocfs2_journal_dirty(handle, *new_fe_bh);
 	if (status < 0) {
@@ -1048,11 +943,6 @@
 		ocfs2_meta_unlock(inode2, 1);
 }
 
-#define PARENT_INO(buffer) \
-	((struct ocfs2_dir_entry *) \
-	 ((char *)buffer + \
-	  le16_to_cpu(((struct ocfs2_dir_entry *)buffer)->rec_len)))->inode
-
 static int ocfs2_rename(struct inode *old_dir,
 			struct dentry *old_dentry,
 			struct inode *new_dir,
@@ -1070,12 +960,12 @@
 	struct buffer_head *old_inode_bh = NULL;
 	struct buffer_head *insert_entry_bh = NULL;
 	struct ocfs2_super *osb = NULL;
-	u64 newfe_blkno;
+	u64 newfe_blkno, old_de_ino;
 	handle_t *handle = NULL;
 	struct buffer_head *old_dir_bh = NULL;
 	struct buffer_head *new_dir_bh = NULL;
-	struct ocfs2_dir_entry *old_de = NULL, *new_de = NULL; // dirent for old_dentry
-							       // and new_dentry
+	struct ocfs2_dir_entry *old_inode_dot_dot_de = NULL, *old_de = NULL,
+		*new_de = NULL;
 	struct buffer_head *new_de_bh = NULL, *old_de_bh = NULL; // bhs for above
 	struct buffer_head *old_inode_de_bh = NULL; // if old_dentry is a dir,
 						    // this is the 1st dirent bh
@@ -1159,27 +1049,35 @@
 	}
 
 	if (S_ISDIR(old_inode->i_mode)) {
-		status = -EIO;
-		old_inode_de_bh = ocfs2_bread(old_inode, 0, &status, 0);
-		if (!old_inode_de_bh)
-			goto bail;
+		u64 old_inode_parent;
 
-		status = -EIO;
-		if (le64_to_cpu(PARENT_INO(old_inode_de_bh->b_data)) !=
-		    OCFS2_I(old_dir)->ip_blkno)
+		status = ocfs2_find_files_on_disk("..", 2, &old_inode_parent,
+						  old_inode, &old_inode_de_bh,
+						  &old_inode_dot_dot_de);
+		if (status) {
+			status = -EIO;
 			goto bail;
-		status = -EMLINK;
-		if (!new_inode && new_dir!=old_dir &&
-		    new_dir->i_nlink >= OCFS2_LINK_MAX)
+		}
+
+		if (old_inode_parent != OCFS2_I(old_dir)->ip_blkno) {
+			status = -EIO;
 			goto bail;
+		}
+
+		if (!new_inode && new_dir != old_dir &&
+		    new_dir->i_nlink >= OCFS2_LINK_MAX) {
+			status = -EMLINK;
+			goto bail;
+		}
 	}
 
-	status = -ENOENT;
-	old_de_bh = ocfs2_find_entry(old_dentry->d_name.name,
-				     old_dentry->d_name.len,
-				     old_dir, &old_de);
-	if (!old_de_bh)
+	status = ocfs2_lookup_ino_from_name(old_dir, old_dentry->d_name.name,
+					    old_dentry->d_name.len,
+					    &old_de_ino);
+	if (status) {
+		status = -ENOENT;
 		goto bail;
+	}
 
 	/*
 	 *  Check for inode number is _not_ due to possible IO errors.
@@ -1187,8 +1085,10 @@
 	 *  and merrily kill the link to whatever was created under the
 	 *  same name. Goodbye sticky bit ;-<
 	 */
-	if (le64_to_cpu(old_de->inode) != OCFS2_I(old_inode)->ip_blkno)
+	if (old_de_ino != OCFS2_I(old_inode)->ip_blkno) {
+		status = -ENOENT;
 		goto bail;
+	}
 
 	/* check if the target already exists (in which case we need
 	 * to delete it */
@@ -1321,20 +1221,13 @@
 		}
 
 		/* change the dirent to point to the correct inode */
-		status = ocfs2_journal_access(handle, new_dir, new_de_bh,
-					      OCFS2_JOURNAL_ACCESS_WRITE);
+		status = ocfs2_update_entry(new_dir, handle, new_de_bh,
+					    new_de, old_inode);
 		if (status < 0) {
 			mlog_errno(status);
 			goto bail;
 		}
-		new_de->inode = cpu_to_le64(OCFS2_I(old_inode)->ip_blkno);
-		new_de->file_type = old_de->file_type;
 		new_dir->i_version++;
-		status = ocfs2_journal_dirty(handle, new_de_bh);
-		if (status < 0) {
-			mlog_errno(status);
-			goto bail;
-		}
 
 		if (S_ISDIR(new_inode->i_mode))
 			newfe->i_links_count = 0;
@@ -1370,7 +1263,21 @@
 	} else
 		mlog_errno(status);
 
-	/* now that the name has been added to new_dir, remove the old name */
+	/*
+	 * Now that the name has been added to new_dir, remove the old name.
+	 *
+	 * We don't keep any directory entry context around until now
+	 * because the insert might have changed the type of directory
+	 * we're dealing with.
+	 */
+	old_de_bh = ocfs2_find_entry(old_dentry->d_name.name,
+				     old_dentry->d_name.len,
+				     old_dir, &old_de);
+	if (!old_de_bh) {
+		status = -EIO;
+		goto bail;
+	}
+
 	status = ocfs2_delete_entry(handle, old_dir, old_de, old_de_bh);
 	if (status < 0) {
 		mlog_errno(status);
@@ -1383,12 +1290,8 @@
 	}
 	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
 	if (old_inode_de_bh) {
-		status = ocfs2_journal_access(handle, old_inode,
-					     old_inode_de_bh,
-					     OCFS2_JOURNAL_ACCESS_WRITE);
-		PARENT_INO(old_inode_de_bh->b_data) =
-			cpu_to_le64(OCFS2_I(new_dir)->ip_blkno);
-		status = ocfs2_journal_dirty(handle, old_inode_de_bh);
+		status = ocfs2_update_entry(old_inode, handle, old_inode_de_bh,
+					    old_inode_dot_dot_de, new_dir);
 		old_dir->i_nlink--;
 		if (new_inode) {
 			new_inode->i_nlink--;
@@ -1767,329 +1670,6 @@
 	return status;
 }
 
-int ocfs2_check_dir_entry(struct inode * dir,
-			  struct ocfs2_dir_entry * de,
-			  struct buffer_head * bh,
-			  unsigned long offset)
-{
-	const char *error_msg = NULL;
-	const int rlen = le16_to_cpu(de->rec_len);
-
-	if (rlen < OCFS2_DIR_REC_LEN(1))
-		error_msg = "rec_len is smaller than minimal";
-	else if (rlen % 4 != 0)
-		error_msg = "rec_len % 4 != 0";
-	else if (rlen < OCFS2_DIR_REC_LEN(de->name_len))
-		error_msg = "rec_len is too small for name_len";
-	else if (((char *) de - bh->b_data) + rlen > dir->i_sb->s_blocksize)
-		error_msg = "directory entry across blocks";
-
-	if (error_msg != NULL)
-		mlog(ML_ERROR, "bad entry in directory #%llu: %s - "
-		     "offset=%lu, inode=%llu, rec_len=%d, name_len=%d\n",
-		     (unsigned long long)OCFS2_I(dir)->ip_blkno, error_msg,
-		     offset, (unsigned long long)le64_to_cpu(de->inode), rlen,
-		     de->name_len);
-	return error_msg == NULL ? 1 : 0;
-}
-
-/* we don't always have a dentry for what we want to add, so people
- * like orphan dir can call this instead.
- *
- * If you pass me insert_bh, I'll skip the search of the other dir
- * blocks and put the record in there.
- */
-static int __ocfs2_add_entry(handle_t *handle,
-			     struct inode *dir,
-			     const char *name, int namelen,
-			     struct inode *inode, u64 blkno,
-			     struct buffer_head *parent_fe_bh,
-			     struct buffer_head *insert_bh)
-{
-	unsigned long offset;
-	unsigned short rec_len;
-	struct ocfs2_dir_entry *de, *de1;
-	struct super_block *sb;
-	int retval, status;
-
-	mlog_entry_void();
-
-	sb = dir->i_sb;
-
-	if (!namelen)
-		return -EINVAL;
-
-	rec_len = OCFS2_DIR_REC_LEN(namelen);
-	offset = 0;
-	de = (struct ocfs2_dir_entry *) insert_bh->b_data;
-	while (1) {
-		BUG_ON((char *)de >= sb->s_blocksize + insert_bh->b_data);
-		/* These checks should've already been passed by the
-		 * prepare function, but I guess we can leave them
-		 * here anyway. */
-		if (!ocfs2_check_dir_entry(dir, de, insert_bh, offset)) {
-			retval = -ENOENT;
-			goto bail;
-		}
-		if (ocfs2_match(namelen, name, de)) {
-			retval = -EEXIST;
-			goto bail;
-		}
-		if (((le64_to_cpu(de->inode) == 0) &&
-		     (le16_to_cpu(de->rec_len) >= rec_len)) ||
-		    (le16_to_cpu(de->rec_len) >=
-		     (OCFS2_DIR_REC_LEN(de->name_len) + rec_len))) {
-			dir->i_mtime = dir->i_ctime = CURRENT_TIME;
-			retval = ocfs2_mark_inode_dirty(handle, dir, parent_fe_bh);
-			if (retval < 0) {
-				mlog_errno(retval);
-				goto bail;
-			}
-
-			status = ocfs2_journal_access(handle, dir, insert_bh,
-						      OCFS2_JOURNAL_ACCESS_WRITE);
-			/* By now the buffer is marked for journaling */
-			offset += le16_to_cpu(de->rec_len);
-			if (le64_to_cpu(de->inode)) {
-				de1 = (struct ocfs2_dir_entry *)((char *) de +
-					OCFS2_DIR_REC_LEN(de->name_len));
-				de1->rec_len =
-					cpu_to_le16(le16_to_cpu(de->rec_len) -
-					OCFS2_DIR_REC_LEN(de->name_len));
-				de->rec_len = cpu_to_le16(OCFS2_DIR_REC_LEN(de->name_len));
-				de = de1;
-			}
-			de->file_type = OCFS2_FT_UNKNOWN;
-			if (blkno) {
-				de->inode = cpu_to_le64(blkno);
-				ocfs2_set_de_type(de, inode->i_mode);
-			} else
-				de->inode = 0;
-			de->name_len = namelen;
-			memcpy(de->name, name, namelen);
-
-			dir->i_version++;
-			status = ocfs2_journal_dirty(handle, insert_bh);
-			retval = 0;
-			goto bail;
-		}
-		offset += le16_to_cpu(de->rec_len);
-		de = (struct ocfs2_dir_entry *) ((char *) de + le16_to_cpu(de->rec_len));
-	}
-
-	/* when you think about it, the assert above should prevent us
-	 * from ever getting here. */
-	retval = -ENOSPC;
-bail:
-
-	mlog_exit(retval);
-	return retval;
-}
-
-
-/*
- * ocfs2_delete_entry deletes a directory entry by merging it with the
- * previous entry
- */
-static int ocfs2_delete_entry(handle_t *handle,
-			      struct inode *dir,
-			      struct ocfs2_dir_entry *de_del,
-			      struct buffer_head *bh)
-{
-	struct ocfs2_dir_entry *de, *pde;
-	int i, status = -ENOENT;
-
-	mlog_entry("(0x%p, 0x%p, 0x%p, 0x%p)\n", handle, dir, de_del, bh);
-
-	i = 0;
-	pde = NULL;
-	de = (struct ocfs2_dir_entry *) bh->b_data;
-	while (i < bh->b_size) {
-		if (!ocfs2_check_dir_entry(dir, de, bh, i)) {
-			status = -EIO;
-			mlog_errno(status);
-			goto bail;
-		}
-		if (de == de_del)  {
-			status = ocfs2_journal_access(handle, dir, bh,
-						      OCFS2_JOURNAL_ACCESS_WRITE);
-			if (status < 0) {
-				status = -EIO;
-				mlog_errno(status);
-				goto bail;
-			}
-			if (pde)
-				pde->rec_len =
-					cpu_to_le16(le16_to_cpu(pde->rec_len) +
-						    le16_to_cpu(de->rec_len));
-			else
-				de->inode = 0;
-			dir->i_version++;
-			status = ocfs2_journal_dirty(handle, bh);
-			goto bail;
-		}
-		i += le16_to_cpu(de->rec_len);
-		pde = de;
-		de = (struct ocfs2_dir_entry *)((char *)de + le16_to_cpu(de->rec_len));
-	}
-bail:
-	mlog_exit(status);
-	return status;
-}
-
-/*
- * Returns 0 if not found, -1 on failure, and 1 on success
- */
-static int inline ocfs2_search_dirblock(struct buffer_head *bh,
-					struct inode *dir,
-					const char *name, int namelen,
-					unsigned long offset,
-					struct ocfs2_dir_entry **res_dir)
-{
-	struct ocfs2_dir_entry *de;
-	char *dlimit, *de_buf;
-	int de_len;
-	int ret = 0;
-
-	mlog_entry_void();
-
-	de_buf = bh->b_data;
-	dlimit = de_buf + dir->i_sb->s_blocksize;
-
-	while (de_buf < dlimit) {
-		/* this code is executed quadratically often */
-		/* do minimal checking `by hand' */
-
-		de = (struct ocfs2_dir_entry *) de_buf;
-
-		if (de_buf + namelen <= dlimit &&
-		    ocfs2_match(namelen, name, de)) {
-			/* found a match - just to be sure, do a full check */
-			if (!ocfs2_check_dir_entry(dir, de, bh, offset)) {
-				ret = -1;
-				goto bail;
-			}
-			*res_dir = de;
-			ret = 1;
-			goto bail;
-		}
-
-		/* prevent looping on a bad block */
-		de_len = le16_to_cpu(de->rec_len);
-		if (de_len <= 0) {
-			ret = -1;
-			goto bail;
-		}
-
-		de_buf += de_len;
-		offset += de_len;
-	}
-
-bail:
-	mlog_exit(ret);
-	return ret;
-}
-
-struct buffer_head *ocfs2_find_entry(const char *name, int namelen,
-				     struct inode *dir,
-				     struct ocfs2_dir_entry **res_dir)
-{
-	struct super_block *sb;
-	struct buffer_head *bh_use[NAMEI_RA_SIZE];
-	struct buffer_head *bh, *ret = NULL;
-	unsigned long start, block, b;
-	int ra_max = 0;		/* Number of bh's in the readahead
-				   buffer, bh_use[] */
-	int ra_ptr = 0;		/* Current index into readahead
-				   buffer */
-	int num = 0;
-	int nblocks, i, err;
-
-	mlog_entry_void();
-
-	*res_dir = NULL;
-	sb = dir->i_sb;
-
-	nblocks = i_size_read(dir) >> sb->s_blocksize_bits;
-	start = OCFS2_I(dir)->ip_dir_start_lookup;
-	if (start >= nblocks)
-		start = 0;
-	block = start;
-
-restart:
-	do {
-		/*
-		 * We deal with the read-ahead logic here.
-		 */
-		if (ra_ptr >= ra_max) {
-			/* Refill the readahead buffer */
-			ra_ptr = 0;
-			b = block;
-			for (ra_max = 0; ra_max < NAMEI_RA_SIZE; ra_max++) {
-				/*
-				 * Terminate if we reach the end of the
-				 * directory and must wrap, or if our
-				 * search has finished at this block.
-				 */
-				if (b >= nblocks || (num && block == start)) {
-					bh_use[ra_max] = NULL;
-					break;
-				}
-				num++;
-
-				bh = ocfs2_bread(dir, b++, &err, 1);
-				bh_use[ra_max] = bh;
-			}
-		}
-		if ((bh = bh_use[ra_ptr++]) == NULL)
-			goto next;
-		wait_on_buffer(bh);
-		if (!buffer_uptodate(bh)) {
-			/* read error, skip block & hope for the best */
-			ocfs2_error(dir->i_sb, "reading directory %llu, "
-				    "offset %lu\n",
-				    (unsigned long long)OCFS2_I(dir)->ip_blkno,
-				    block);
-			brelse(bh);
-			goto next;
-		}
-		i = ocfs2_search_dirblock(bh, dir, name, namelen,
-					  block << sb->s_blocksize_bits,
-					  res_dir);
-		if (i == 1) {
-			OCFS2_I(dir)->ip_dir_start_lookup = block;
-			ret = bh;
-			goto cleanup_and_exit;
-		} else {
-			brelse(bh);
-			if (i < 0)
-				goto cleanup_and_exit;
-		}
-	next:
-		if (++block >= nblocks)
-			block = 0;
-	} while (block != start);
-
-	/*
-	 * If the directory has grown while we were searching, then
-	 * search the last part of the directory before giving up.
-	 */
-	block = nblocks;
-	nblocks = i_size_read(dir) >> sb->s_blocksize_bits;
-	if (block < nblocks) {
-		start = 0;
-		goto restart;
-	}
-
-cleanup_and_exit:
-	/* Clean up the read-ahead blocks */
-	for (; ra_ptr < ra_max; ra_ptr++)
-		brelse(bh_use[ra_ptr]);
-
-	mlog_exit_ptr(ret);
-	return ret;
-}
-
 static int ocfs2_blkno_stringify(u64 blkno, char *name)
 {
 	int status, namelen;
diff --git a/fs/ocfs2/namei.h b/fs/ocfs2/namei.h
index 0975c7b..688aef6 100644
--- a/fs/ocfs2/namei.h
+++ b/fs/ocfs2/namei.h
@@ -30,29 +30,10 @@
 
 struct dentry *ocfs2_get_parent(struct dentry *child);
 
-int ocfs2_check_dir_entry (struct inode *dir,
-			   struct ocfs2_dir_entry *de,
-			   struct buffer_head *bh,
-			   unsigned long offset);
-struct buffer_head *ocfs2_find_entry(const char *name,
-				     int namelen,
-				     struct inode *dir,
-				     struct ocfs2_dir_entry **res_dir);
 int ocfs2_orphan_del(struct ocfs2_super *osb,
 		     handle_t *handle,
 		     struct inode *orphan_dir_inode,
 		     struct inode *inode,
 		     struct buffer_head *orphan_dir_bh);
 
-static inline int ocfs2_match(int len,
-			      const char * const name,
-			      struct ocfs2_dir_entry *de)
-{
-	if (len != de->name_len)
-		return 0;
-	if (!de->inode)
-		return 0;
-	return !memcmp(name, de->name, len);
-}
-
 #endif /* OCFS2_NAMEI_H */
diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h
index 5830785..60a23e1 100644
--- a/fs/ocfs2/ocfs2.h
+++ b/fs/ocfs2/ocfs2.h
@@ -319,6 +319,13 @@
 	return 0;
 }
 
+static inline int ocfs2_supports_inline_data(struct ocfs2_super *osb)
+{
+	if (osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_INLINE_DATA)
+		return 1;
+	return 0;
+}
+
 /* set / clear functions because cluster events can make these happen
  * in parallel so we want the transitions to be atomic. this also
  * means that any future flags osb_flags must be protected by spinlock
diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h
index 82f8a75..6ef8767 100644
--- a/fs/ocfs2/ocfs2_fs.h
+++ b/fs/ocfs2/ocfs2_fs.h
@@ -87,7 +87,8 @@
 
 #define OCFS2_FEATURE_COMPAT_SUPP	OCFS2_FEATURE_COMPAT_BACKUP_SB
 #define OCFS2_FEATURE_INCOMPAT_SUPP	(OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT \
-					 | OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC)
+					 | OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC \
+					 | OCFS2_FEATURE_INCOMPAT_INLINE_DATA)
 #define OCFS2_FEATURE_RO_COMPAT_SUPP	OCFS2_FEATURE_RO_COMPAT_UNWRITTEN
 
 /*
@@ -111,6 +112,20 @@
 #define OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC	0x0010
 
 /*
+ * Tunefs sets this incompat flag before starting an operation which
+ * would require cleanup on abort. This is done to protect users from
+ * inadvertently mounting the fs after an aborted run without
+ * fsck-ing.
+ *
+ * s_tunefs_flags on the super block describes precisely which
+ * operations were in progress.
+ */
+#define OCFS2_FEATURE_INCOMPAT_TUNEFS_INPROG	0x0020
+
+/* Support for data packed into inode blocks */
+#define OCFS2_FEATURE_INCOMPAT_INLINE_DATA	0x0040
+
+/*
  * backup superblock flag is used to indicate that this volume
  * has backup superblocks.
  */
@@ -130,6 +145,11 @@
 #define OCFS2_MAX_BACKUP_SUPERBLOCKS	6
 
 /*
+ * Flags on ocfs2_super_block.s_tunefs_flags
+ */
+#define OCFS2_TUNEFS_INPROG_REMOVE_SLOT		0x0001	/* Removing slots */
+
+/*
  * Flags on ocfs2_dinode.i_flags
  */
 #define OCFS2_VALID_FL		(0x00000001)	/* Inode is valid */
@@ -146,6 +166,17 @@
 #define OCFS2_CHAIN_FL		(0x00000400)	/* Chain allocator */
 #define OCFS2_DEALLOC_FL	(0x00000800)	/* Truncate log */
 
+/*
+ * Flags on ocfs2_dinode.i_dyn_features
+ *
+ * These can change much more often than i_flags. When adding flags,
+ * keep in mind that i_dyn_features is only 16 bits wide.
+ */
+#define OCFS2_INLINE_DATA_FL	(0x0001)	/* Data stored in inode block */
+#define OCFS2_HAS_XATTR_FL	(0x0002)
+#define OCFS2_INLINE_XATTR_FL	(0x0004)
+#define OCFS2_INDEXED_DIR_FL	(0x0008)
+
 /* Inode attributes, keep in sync with EXT2 */
 #define OCFS2_SECRM_FL		(0x00000001)	/* Secure deletion */
 #define OCFS2_UNRM_FL		(0x00000002)	/* Undelete */
@@ -447,8 +478,8 @@
 	__le32 s_clustersize_bits;	/* Clustersize for this fs */
 /*40*/	__le16 s_max_slots;		/* Max number of simultaneous mounts
 					   before tunefs required */
-	__le16 s_reserved1;
-	__le32 s_reserved2;
+	__le16 s_tunefs_flag;
+	__le32 s_reserved1;
 	__le64 s_first_cluster_group;	/* Block offset of 1st cluster
 					 * group header */
 /*50*/	__u8  s_label[OCFS2_MAX_VOL_LABEL_LEN];	/* Label for mounting, etc. */
@@ -471,6 +502,19 @@
 };
 
 /*
+ * Data-in-inode header. This is only used if i_dyn_features has
+ * OCFS2_INLINE_DATA_FL set.
+ */
+struct ocfs2_inline_data
+{
+/*00*/	__le16	id_count;	/* Number of bytes that can be used
+				 * for data, starting at id_data */
+	__le16	id_reserved0;
+	__le32	id_reserved1;
+	__u8	id_data[0];	/* Start of user data */
+};
+
+/*
  * On disk inode for OCFS2
  */
 struct ocfs2_dinode {
@@ -502,7 +546,7 @@
 	__le32 i_attr;
 	__le16 i_orphaned_slot;		/* Only valid when OCFS2_ORPHANED_FL
 					   was set in i_flags */
-	__le16 i_reserved1;
+	__le16 i_dyn_features;
 /*70*/	__le64 i_reserved2[8];
 /*B8*/	union {
 		__le64 i_pad1;		/* Generic way to refer to this
@@ -528,6 +572,7 @@
 		struct ocfs2_chain_list		i_chain;
 		struct ocfs2_extent_list	i_list;
 		struct ocfs2_truncate_log	i_dealloc;
+		struct ocfs2_inline_data	i_data;
 		__u8               		i_symlink[0];
 	} id2;
 /* Actual on-disk size is one block */
@@ -577,6 +622,12 @@
 		 offsetof(struct ocfs2_dinode, id2.i_symlink);
 }
 
+static inline int ocfs2_max_inline_data(struct super_block *sb)
+{
+	return sb->s_blocksize -
+		offsetof(struct ocfs2_dinode, id2.i_data.id_data);
+}
+
 static inline int ocfs2_extent_recs_per_inode(struct super_block *sb)
 {
 	int size;
@@ -656,6 +707,11 @@
 	return blocksize - offsetof(struct ocfs2_dinode, id2.i_symlink);
 }
 
+static inline int ocfs2_max_inline_data(int blocksize)
+{
+	return blocksize - offsetof(struct ocfs2_dinode, id2.i_data.id_data);
+}
+
 static inline int ocfs2_extent_recs_per_inode(int blocksize)
 {
 	int size;
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index c034b51..0e2a1b4 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -39,6 +39,7 @@
 #include <linux/parser.h>
 #include <linux/crc32.h>
 #include <linux/debugfs.h>
+#include <linux/mount.h>
 
 #include <cluster/nodemanager.h>
 
@@ -91,6 +92,7 @@
 static int ocfs2_parse_options(struct super_block *sb, char *options,
 			       struct mount_options *mopt,
 			       int is_remount);
+static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt);
 static void ocfs2_put_super(struct super_block *sb);
 static int ocfs2_mount_volume(struct super_block *sb);
 static int ocfs2_remount(struct super_block *sb, int *flags, char *data);
@@ -105,7 +107,7 @@
 
 static int ocfs2_init_global_system_inodes(struct ocfs2_super *osb);
 static int ocfs2_init_local_system_inodes(struct ocfs2_super *osb);
-static int ocfs2_release_system_inodes(struct ocfs2_super *osb);
+static void ocfs2_release_system_inodes(struct ocfs2_super *osb);
 static int ocfs2_fill_local_node_info(struct ocfs2_super *osb);
 static int ocfs2_check_volume(struct ocfs2_super *osb);
 static int ocfs2_verify_volume(struct ocfs2_dinode *di,
@@ -133,6 +135,7 @@
 	.write_super	= ocfs2_write_super,
 	.put_super	= ocfs2_put_super,
 	.remount_fs	= ocfs2_remount,
+	.show_options   = ocfs2_show_options,
 };
 
 enum {
@@ -177,7 +180,7 @@
 
 static int ocfs2_sync_fs(struct super_block *sb, int wait)
 {
-	int status = 0;
+	int status;
 	tid_t target;
 	struct ocfs2_super *osb = OCFS2_SB(sb);
 
@@ -275,9 +278,9 @@
 	return status;
 }
 
-static int ocfs2_release_system_inodes(struct ocfs2_super *osb)
+static void ocfs2_release_system_inodes(struct ocfs2_super *osb)
 {
-	int status = 0, i;
+	int i;
 	struct inode *inode;
 
 	mlog_entry_void();
@@ -302,8 +305,7 @@
 		osb->root_inode = NULL;
 	}
 
-	mlog_exit(status);
-	return status;
+	mlog_exit(0);
 }
 
 /* We're allocating fs objects, use GFP_NOFS */
@@ -453,7 +455,7 @@
 			  struct buffer_head **bh,
 			  int *sector_size)
 {
-	int status = 0, tmpstat;
+	int status, tmpstat;
 	struct ocfs1_vol_disk_hdr *hdr;
 	struct ocfs2_dinode *di;
 	int blksize;
@@ -830,6 +832,41 @@
 	return status;
 }
 
+static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt)
+{
+	struct ocfs2_super *osb = OCFS2_SB(mnt->mnt_sb);
+	unsigned long opts = osb->s_mount_opt;
+
+	if (opts & OCFS2_MOUNT_HB_LOCAL)
+		seq_printf(s, ",_netdev,heartbeat=local");
+	else
+		seq_printf(s, ",heartbeat=none");
+
+	if (opts & OCFS2_MOUNT_NOINTR)
+		seq_printf(s, ",nointr");
+
+	if (opts & OCFS2_MOUNT_DATA_WRITEBACK)
+		seq_printf(s, ",data=writeback");
+	else
+		seq_printf(s, ",data=ordered");
+
+	if (opts & OCFS2_MOUNT_BARRIER)
+		seq_printf(s, ",barrier=1");
+
+	if (opts & OCFS2_MOUNT_ERRORS_PANIC)
+		seq_printf(s, ",errors=panic");
+	else
+		seq_printf(s, ",errors=remount-ro");
+
+	if (osb->preferred_slot != OCFS2_INVALID_SLOT)
+		seq_printf(s, ",preferred_slot=%d", osb->preferred_slot);
+
+	if (osb->s_atime_quantum != OCFS2_DEFAULT_ATIME_QUANTUM)
+		seq_printf(s, ",atime_quantum=%u", osb->s_atime_quantum);
+
+	return 0;
+}
+
 static int __init ocfs2_init(void)
 {
 	int status;
@@ -1209,13 +1246,14 @@
 		tmp = ocfs2_request_umount_vote(osb);
 		if (tmp < 0)
 			mlog_errno(tmp);
-
-		if (osb->slot_num != OCFS2_INVALID_SLOT)
-			ocfs2_put_slot(osb);
-
-		ocfs2_super_unlock(osb, 1);
 	}
 
+	if (osb->slot_num != OCFS2_INVALID_SLOT)
+		ocfs2_put_slot(osb);
+
+	if (osb->dlm)
+		ocfs2_super_unlock(osb, 1);
+
 	ocfs2_release_system_inodes(osb);
 
 	if (osb->dlm) {
@@ -1275,7 +1313,7 @@
 				  struct buffer_head *bh,
 				  int sector_size)
 {
-	int status = 0;
+	int status;
 	int i, cbits, bbits;
 	struct ocfs2_dinode *di = (struct ocfs2_dinode *)bh->b_data;
 	struct inode *inode = NULL;
@@ -1596,7 +1634,7 @@
 
 static int ocfs2_check_volume(struct ocfs2_super *osb)
 {
-	int status = 0;
+	int status;
 	int dirty;
 	int local;
 	struct ocfs2_dinode *local_alloc = NULL; /* only used if we
diff --git a/fs/ocfs2/sysfile.c b/fs/ocfs2/sysfile.c
index 5df6e35..fd2e846 100644
--- a/fs/ocfs2/sysfile.c
+++ b/fs/ocfs2/sysfile.c
@@ -100,17 +100,14 @@
 	char namebuf[40];
 	struct inode *inode = NULL;
 	u64 blkno;
-	struct buffer_head *dirent_bh = NULL;
-	struct ocfs2_dir_entry *de = NULL;
 	int status = 0;
 
 	ocfs2_sprintf_system_inode_name(namebuf,
 					sizeof(namebuf),
 					type, slot);
 
-	status = ocfs2_find_files_on_disk(namebuf, strlen(namebuf),
-					  &blkno, osb->sys_root_inode,
-					  &dirent_bh, &de);
+	status = ocfs2_lookup_ino_from_name(osb->sys_root_inode, namebuf,
+					    strlen(namebuf), &blkno);
 	if (status < 0) {
 		goto bail;
 	}
@@ -122,8 +119,7 @@
 		goto bail;
 	}
 bail:
-	if (dirent_bh)
-		brelse(dirent_bh);
+
 	return inode;
 }
 
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index 783c57e..722e12e 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -381,10 +381,12 @@
 	p->partno = part;
 	p->policy = disk->policy;
 
-	if (isdigit(disk->kobj.name[strlen(disk->kobj.name)-1]))
-		snprintf(p->kobj.name,KOBJ_NAME_LEN,"%sp%d",disk->kobj.name,part);
+	if (isdigit(disk->kobj.k_name[strlen(disk->kobj.k_name)-1]))
+		kobject_set_name(&p->kobj, "%sp%d",
+				 kobject_name(&disk->kobj), part);
 	else
-		snprintf(p->kobj.name,KOBJ_NAME_LEN,"%s%d",disk->kobj.name,part);
+		kobject_set_name(&p->kobj, "%s%d",
+				 kobject_name(&disk->kobj),part);
 	p->kobj.parent = &disk->kobj;
 	p->kobj.ktype = &ktype_part;
 	kobject_init(&p->kobj);
@@ -477,9 +479,9 @@
 	struct hd_struct *p;
 	int err;
 
-	strlcpy(disk->kobj.name,disk->disk_name,KOBJ_NAME_LEN);
+	kobject_set_name(&disk->kobj, "%s", disk->disk_name);
 	/* ewww... some of these buggers have / in name... */
-	s = strchr(disk->kobj.name, '/');
+	s = strchr(disk->kobj.k_name, '/');
 	if (s)
 		*s = '!';
 	if ((err = kobject_add(&disk->kobj)))
diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c
index 5afe2a2..006fc64 100644
--- a/fs/sysfs/bin.c
+++ b/fs/sysfs/bin.c
@@ -1,9 +1,15 @@
 /*
- * bin.c - binary file operations for sysfs.
+ * fs/sysfs/bin.c - sysfs binary file implementation
  *
  * Copyright (c) 2003 Patrick Mochel
  * Copyright (c) 2003 Matthew Wilcox
  * Copyright (c) 2004 Silicon Graphics, Inc.
+ * Copyright (c) 2007 SUSE Linux Products GmbH
+ * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
+ *
+ * This file is released under the GPLv2.
+ *
+ * Please see Documentation/filesystems/sysfs.txt for more information.
  */
 
 #undef DEBUG
@@ -14,9 +20,9 @@
 #include <linux/kobject.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/mutex.h>
 
 #include <asm/uaccess.h>
-#include <asm/semaphore.h>
 
 #include "sysfs.h"
 
@@ -30,8 +36,8 @@
 fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count)
 {
 	struct sysfs_dirent *attr_sd = dentry->d_fsdata;
-	struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;
-	struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
+	struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr;
+	struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
 	int rc;
 
 	/* need attr_sd for attr, its parent for kobj */
@@ -87,8 +93,8 @@
 flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count)
 {
 	struct sysfs_dirent *attr_sd = dentry->d_fsdata;
-	struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;
-	struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
+	struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr;
+	struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
 	int rc;
 
 	/* need attr_sd for attr, its parent for kobj */
@@ -140,8 +146,8 @@
 {
 	struct bin_buffer *bb = file->private_data;
 	struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
-	struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;
-	struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
+	struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr;
+	struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
 	int rc;
 
 	mutex_lock(&bb->mutex);
@@ -167,12 +173,12 @@
 static int open(struct inode * inode, struct file * file)
 {
 	struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
-	struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;
+	struct bin_attribute *attr = attr_sd->s_bin_attr.bin_attr;
 	struct bin_buffer *bb = NULL;
 	int error;
 
-	/* need attr_sd for attr */
-	if (!sysfs_get_active(attr_sd))
+	/* binary file operations requires both @sd and its parent */
+	if (!sysfs_get_active_two(attr_sd))
 		return -ENODEV;
 
 	error = -EACCES;
@@ -193,13 +199,12 @@
 	mutex_init(&bb->mutex);
 	file->private_data = bb;
 
-	/* open succeeded, put active reference and pin attr_sd */
-	sysfs_put_active(attr_sd);
-	sysfs_get(attr_sd);
+	/* open succeeded, put active references */
+	sysfs_put_active_two(attr_sd);
 	return 0;
 
  err_out:
-	sysfs_put_active(attr_sd);
+	sysfs_put_active_two(attr_sd);
 	kfree(bb);
 	return error;
 }
@@ -211,7 +216,6 @@
 
 	if (bb->mmapped)
 		sysfs_put_active_two(attr_sd);
-	sysfs_put(attr_sd);
 	kfree(bb->buffer);
 	kfree(bb);
 	return 0;
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 83e76b3..9161db4 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -1,5 +1,13 @@
 /*
- * dir.c - Operations for sysfs directories.
+ * fs/sysfs/dir.c - sysfs core and dir operation implementation
+ *
+ * Copyright (c) 2001-3 Patrick Mochel
+ * Copyright (c) 2007 SUSE Linux Products GmbH
+ * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
+ *
+ * This file is released under the GPLv2.
+ *
+ * Please see Documentation/filesystems/sysfs.txt for more information.
  */
 
 #undef DEBUG
@@ -11,10 +19,11 @@
 #include <linux/namei.h>
 #include <linux/idr.h>
 #include <linux/completion.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include "sysfs.h"
 
 DEFINE_MUTEX(sysfs_mutex);
+DEFINE_MUTEX(sysfs_rename_mutex);
 spinlock_t sysfs_assoc_lock = SPIN_LOCK_UNLOCKED;
 
 static spinlock_t sysfs_ino_lock = SPIN_LOCK_UNLOCKED;
@@ -25,18 +34,28 @@
  *	@sd: sysfs_dirent of interest
  *
  *	Link @sd into its sibling list which starts from
- *	sd->s_parent->s_children.
+ *	sd->s_parent->s_dir.children.
  *
  *	Locking:
  *	mutex_lock(sysfs_mutex)
  */
-void sysfs_link_sibling(struct sysfs_dirent *sd)
+static void sysfs_link_sibling(struct sysfs_dirent *sd)
 {
 	struct sysfs_dirent *parent_sd = sd->s_parent;
+	struct sysfs_dirent **pos;
 
 	BUG_ON(sd->s_sibling);
-	sd->s_sibling = parent_sd->s_children;
-	parent_sd->s_children = sd;
+
+	/* Store directory entries in order by ino.  This allows
+	 * readdir to properly restart without having to add a
+	 * cursor into the s_dir.children list.
+	 */
+	for (pos = &parent_sd->s_dir.children; *pos; pos = &(*pos)->s_sibling) {
+		if (sd->s_ino < (*pos)->s_ino)
+			break;
+	}
+	sd->s_sibling = *pos;
+	*pos = sd;
 }
 
 /**
@@ -44,16 +63,17 @@
  *	@sd: sysfs_dirent of interest
  *
  *	Unlink @sd from its sibling list which starts from
- *	sd->s_parent->s_children.
+ *	sd->s_parent->s_dir.children.
  *
  *	Locking:
  *	mutex_lock(sysfs_mutex)
  */
-void sysfs_unlink_sibling(struct sysfs_dirent *sd)
+static void sysfs_unlink_sibling(struct sysfs_dirent *sd)
 {
 	struct sysfs_dirent **pos;
 
-	for (pos = &sd->s_parent->s_children; *pos; pos = &(*pos)->s_sibling) {
+	for (pos = &sd->s_parent->s_dir.children; *pos;
+	     pos = &(*pos)->s_sibling) {
 		if (*pos == sd) {
 			*pos = sd->s_sibling;
 			sd->s_sibling = NULL;
@@ -67,96 +87,39 @@
  *	@sd: sysfs_dirent of interest
  *
  *	Get dentry for @sd.  Dentry is looked up if currently not
- *	present.  This function climbs sysfs_dirent tree till it
- *	reaches a sysfs_dirent with valid dentry attached and descends
- *	down from there looking up dentry for each step.
+ *	present.  This function descends from the root looking up
+ *	dentry for each step.
  *
  *	LOCKING:
- *	Kernel thread context (may sleep)
+ *	mutex_lock(sysfs_rename_mutex)
  *
  *	RETURNS:
  *	Pointer to found dentry on success, ERR_PTR() value on error.
  */
 struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd)
 {
-	struct sysfs_dirent *cur;
-	struct dentry *parent_dentry, *dentry;
-	int i, depth;
+	struct dentry *dentry = dget(sysfs_sb->s_root);
 
-	/* Find the first parent which has valid s_dentry and get the
-	 * dentry.
-	 */
-	mutex_lock(&sysfs_mutex);
- restart0:
-	spin_lock(&sysfs_assoc_lock);
- restart1:
-	spin_lock(&dcache_lock);
+	while (dentry->d_fsdata != sd) {
+		struct sysfs_dirent *cur;
+		struct dentry *parent;
 
-	dentry = NULL;
-	depth = 0;
-	cur = sd;
-	while (!cur->s_dentry || !cur->s_dentry->d_inode) {
-		if (cur->s_flags & SYSFS_FLAG_REMOVED) {
-			dentry = ERR_PTR(-ENOENT);
-			depth = 0;
-			break;
-		}
-		cur = cur->s_parent;
-		depth++;
-	}
-	if (!IS_ERR(dentry))
-		dentry = dget_locked(cur->s_dentry);
-
-	spin_unlock(&dcache_lock);
-	spin_unlock(&sysfs_assoc_lock);
-
-	/* from the found dentry, look up depth times */
-	while (depth--) {
-		/* find and get depth'th ancestor */
-		for (cur = sd, i = 0; cur && i < depth; i++)
+		/* find the first ancestor which hasn't been looked up */
+		cur = sd;
+		while (cur->s_parent != dentry->d_fsdata)
 			cur = cur->s_parent;
 
-		/* This can happen if tree structure was modified due
-		 * to move/rename.  Restart.
-		 */
-		if (i != depth) {
-			dput(dentry);
-			goto restart0;
-		}
-
-		sysfs_get(cur);
-
-		mutex_unlock(&sysfs_mutex);
-
 		/* look it up */
-		parent_dentry = dentry;
-		dentry = lookup_one_len_kern(cur->s_name, parent_dentry,
+		parent = dentry;
+		mutex_lock(&parent->d_inode->i_mutex);
+		dentry = lookup_one_len_kern(cur->s_name, parent,
 					     strlen(cur->s_name));
-		dput(parent_dentry);
+		mutex_unlock(&parent->d_inode->i_mutex);
+		dput(parent);
 
-		if (IS_ERR(dentry)) {
-			sysfs_put(cur);
-			return dentry;
-		}
-
-		mutex_lock(&sysfs_mutex);
-		spin_lock(&sysfs_assoc_lock);
-
-		/* This, again, can happen if tree structure has
-		 * changed and we looked up the wrong thing.  Restart.
-		 */
-		if (cur->s_dentry != dentry) {
-			dput(dentry);
-			sysfs_put(cur);
-			goto restart1;
-		}
-
-		spin_unlock(&sysfs_assoc_lock);
-
-		sysfs_put(cur);
+		if (IS_ERR(dentry))
+			break;
 	}
-
-	mutex_unlock(&sysfs_mutex);
 	return dentry;
 }
 
@@ -319,7 +282,7 @@
 	parent_sd = sd->s_parent;
 
 	if (sysfs_type(sd) == SYSFS_KOBJ_LINK)
-		sysfs_put(sd->s_elem.symlink.target_sd);
+		sysfs_put(sd->s_symlink.target_sd);
 	if (sysfs_type(sd) & SYSFS_COPY_NAME)
 		kfree(sd->s_name);
 	kfree(sd->s_iattr);
@@ -335,22 +298,7 @@
 {
 	struct sysfs_dirent * sd = dentry->d_fsdata;
 
-	if (sd) {
-		/* sd->s_dentry is protected with sysfs_assoc_lock.
-		 * This allows sysfs_drop_dentry() to dereference it.
-		 */
-		spin_lock(&sysfs_assoc_lock);
-
-		/* The dentry might have been deleted or another
-		 * lookup could have happened updating sd->s_dentry to
-		 * point the new dentry.  Ignore if it isn't pointing
-		 * to this dentry.
-		 */
-		if (sd->s_dentry == dentry)
-			sd->s_dentry = NULL;
-		spin_unlock(&sysfs_assoc_lock);
-		sysfs_put(sd);
-	}
+	sysfs_put(sd);
 	iput(inode);
 }
 
@@ -378,7 +326,6 @@
 
 	atomic_set(&sd->s_count, 1);
 	atomic_set(&sd->s_active, 0);
-	atomic_set(&sd->s_event, 1);
 
 	sd->s_name = name;
 	sd->s_mode = mode;
@@ -393,30 +340,6 @@
 	return NULL;
 }
 
-/**
- *	sysfs_attach_dentry - associate sysfs_dirent with dentry
- *	@sd: target sysfs_dirent
- *	@dentry: dentry to associate
- *
- *	Associate @sd with @dentry.  This is protected by
- *	sysfs_assoc_lock to avoid race with sysfs_d_iput().
- *
- *	LOCKING:
- *	mutex_lock(sysfs_mutex)
- */
-static void sysfs_attach_dentry(struct sysfs_dirent *sd, struct dentry *dentry)
-{
-	dentry->d_op = &sysfs_dentry_ops;
-	dentry->d_fsdata = sysfs_get(sd);
-
-	/* protect sd->s_dentry against sysfs_d_iput */
-	spin_lock(&sysfs_assoc_lock);
-	sd->s_dentry = dentry;
-	spin_unlock(&sysfs_assoc_lock);
-
-	d_rehash(dentry);
-}
-
 static int sysfs_ilookup_test(struct inode *inode, void *arg)
 {
 	struct sysfs_dirent *sd = arg;
@@ -480,10 +403,8 @@
  *	@sd: sysfs_dirent to be added
  *
  *	Get @acxt->parent_sd and set sd->s_parent to it and increment
- *	nlink of parent inode if @sd is a directory.  @sd is NOT
- *	linked into the children list of the parent.  The caller
- *	should invoke sysfs_link_sibling() after this function
- *	completes if @sd needs to be on the children list.
+ *	nlink of parent inode if @sd is a directory and link into the
+ *	children list of the parent.
  *
  *	This function should be called between calls to
  *	sysfs_addrm_start() and sysfs_addrm_finish() and should be
@@ -491,15 +412,30 @@
  *
  *	LOCKING:
  *	Determined by sysfs_addrm_start().
+ *
+ *	RETURNS:
+ *	0 on success, -EEXIST if entry with the given name already
+ *	exists.
  */
-void sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
+int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
 {
+	if (sysfs_find_dirent(acxt->parent_sd, sd->s_name)) {
+		printk(KERN_WARNING "sysfs: duplicate filename '%s' "
+		       "can not be created\n", sd->s_name);
+		WARN_ON(1);
+		return -EEXIST;
+	}
+
 	sd->s_parent = sysfs_get(acxt->parent_sd);
 
 	if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode)
 		inc_nlink(acxt->parent_inode);
 
 	acxt->cnt++;
+
+	sysfs_link_sibling(sd);
+
+	return 0;
 }
 
 /**
@@ -508,9 +444,7 @@
  *	@sd: sysfs_dirent to be added
  *
  *	Mark @sd removed and drop nlink of parent inode if @sd is a
- *	directory.  @sd is NOT unlinked from the children list of the
- *	parent.  The caller is repsonsible for removing @sd from the
- *	children list before calling this function.
+ *	directory.  @sd is unlinked from the children list.
  *
  *	This function should be called between calls to
  *	sysfs_addrm_start() and sysfs_addrm_finish() and should be
@@ -521,7 +455,9 @@
  */
 void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
 {
-	BUG_ON(sd->s_sibling || (sd->s_flags & SYSFS_FLAG_REMOVED));
+	BUG_ON(sd->s_flags & SYSFS_FLAG_REMOVED);
+
+	sysfs_unlink_sibling(sd);
 
 	sd->s_flags |= SYSFS_FLAG_REMOVED;
 	sd->s_sibling = acxt->removed;
@@ -540,53 +476,49 @@
  *	Drop dentry for @sd.  @sd must have been unlinked from its
  *	parent on entry to this function such that it can't be looked
  *	up anymore.
- *
- *	@sd->s_dentry which is protected with sysfs_assoc_lock points
- *	to the currently associated dentry but we're not holding a
- *	reference to it and racing with dput().  Grab dcache_lock and
- *	verify dentry before dropping it.  If @sd->s_dentry is NULL or
- *	dput() beats us, no need to bother.
  */
 static void sysfs_drop_dentry(struct sysfs_dirent *sd)
 {
-	struct dentry *dentry = NULL;
 	struct inode *inode;
+	struct dentry *dentry;
 
-	/* We're not holding a reference to ->s_dentry dentry but the
-	 * field will stay valid as long as sysfs_assoc_lock is held.
+	inode = ilookup(sysfs_sb, sd->s_ino);
+	if (!inode)
+		return;
+
+	/* Drop any existing dentries associated with sd.
+	 *
+	 * For the dentry to be properly freed we need to grab a
+	 * reference to the dentry under the dcache lock,  unhash it,
+	 * and then put it.  The playing with the dentry count allows
+	 * dput to immediately free the dentry  if it is not in use.
 	 */
-	spin_lock(&sysfs_assoc_lock);
+repeat:
 	spin_lock(&dcache_lock);
-
-	/* drop dentry if it's there and dput() didn't kill it yet */
-	if (sd->s_dentry && sd->s_dentry->d_inode) {
-		dentry = dget_locked(sd->s_dentry);
+	list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+		if (d_unhashed(dentry))
+			continue;
+		dget_locked(dentry);
 		spin_lock(&dentry->d_lock);
 		__d_drop(dentry);
 		spin_unlock(&dentry->d_lock);
-	}
-
-	spin_unlock(&dcache_lock);
-	spin_unlock(&sysfs_assoc_lock);
-
-	/* dentries for shadowed inodes are pinned, unpin */
-	if (dentry && sysfs_is_shadowed_inode(dentry->d_inode))
+		spin_unlock(&dcache_lock);
 		dput(dentry);
-	dput(dentry);
+		goto repeat;
+	}
+	spin_unlock(&dcache_lock);
 
 	/* adjust nlink and update timestamp */
-	inode = ilookup(sysfs_sb, sd->s_ino);
-	if (inode) {
-		mutex_lock(&inode->i_mutex);
+	mutex_lock(&inode->i_mutex);
 
-		inode->i_ctime = CURRENT_TIME;
+	inode->i_ctime = CURRENT_TIME;
+	drop_nlink(inode);
+	if (sysfs_type(sd) == SYSFS_DIR)
 		drop_nlink(inode);
-		if (sysfs_type(sd) == SYSFS_DIR)
-			drop_nlink(inode);
 
-		mutex_unlock(&inode->i_mutex);
-		iput(inode);
-	}
+	mutex_unlock(&inode->i_mutex);
+
+	iput(inode);
 }
 
 /**
@@ -599,11 +531,8 @@
  *
  *	LOCKING:
  *	All mutexes acquired by sysfs_addrm_start() are released.
- *
- *	RETURNS:
- *	Number of added/removed sysfs_dirents since sysfs_addrm_start().
  */
-int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)
+void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)
 {
 	/* release resources acquired by sysfs_addrm_start() */
 	mutex_unlock(&sysfs_mutex);
@@ -629,8 +558,6 @@
 		sysfs_deactivate(sd);
 		sysfs_put(sd);
 	}
-
-	return acxt->cnt;
 }
 
 /**
@@ -651,8 +578,8 @@
 {
 	struct sysfs_dirent *sd;
 
-	for (sd = parent_sd->s_children; sd; sd = sd->s_sibling)
-		if (sysfs_type(sd) && !strcmp(sd->s_name, name))
+	for (sd = parent_sd->s_dir.children; sd; sd = sd->s_sibling)
+		if (!strcmp(sd->s_name, name))
 			return sd;
 	return NULL;
 }
@@ -690,28 +617,25 @@
 	umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
 	struct sysfs_addrm_cxt acxt;
 	struct sysfs_dirent *sd;
+	int rc;
 
 	/* allocate */
 	sd = sysfs_new_dirent(name, mode, SYSFS_DIR);
 	if (!sd)
 		return -ENOMEM;
-	sd->s_elem.dir.kobj = kobj;
+	sd->s_dir.kobj = kobj;
 
 	/* link in */
 	sysfs_addrm_start(&acxt, parent_sd);
+	rc = sysfs_add_one(&acxt, sd);
+	sysfs_addrm_finish(&acxt);
 
-	if (!sysfs_find_dirent(parent_sd, name)) {
-		sysfs_add_one(&acxt, sd);
-		sysfs_link_sibling(sd);
-	}
-
-	if (!sysfs_addrm_finish(&acxt)) {
+	if (rc == 0)
+		*p_sd = sd;
+	else
 		sysfs_put(sd);
-		return -EEXIST;
-	}
 
-	*p_sd = sd;
-	return 0;
+	return rc;
 }
 
 int sysfs_create_subdir(struct kobject *kobj, const char *name,
@@ -723,24 +647,18 @@
 /**
  *	sysfs_create_dir - create a directory for an object.
  *	@kobj:		object we're creating directory for. 
- *	@shadow_parent:	parent object.
  */
-int sysfs_create_dir(struct kobject *kobj,
-		     struct sysfs_dirent *shadow_parent_sd)
+int sysfs_create_dir(struct kobject * kobj)
 {
 	struct sysfs_dirent *parent_sd, *sd;
 	int error = 0;
 
 	BUG_ON(!kobj);
 
-	if (shadow_parent_sd)
-		parent_sd = shadow_parent_sd;
-	else if (kobj->parent)
+	if (kobj->parent)
 		parent_sd = kobj->parent->sd;
-	else if (sysfs_mount && sysfs_mount->mnt_sb)
-		parent_sd = sysfs_mount->mnt_sb->s_root->d_fsdata;
 	else
-		return -EFAULT;
+		parent_sd = &sysfs_root;
 
 	error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd);
 	if (!error)
@@ -748,39 +666,20 @@
 	return error;
 }
 
-static int sysfs_count_nlink(struct sysfs_dirent *sd)
-{
-	struct sysfs_dirent *child;
-	int nr = 0;
-
-	for (child = sd->s_children; child; child = child->s_sibling)
-		if (sysfs_type(child) == SYSFS_DIR)
-			nr++;
-	return nr + 2;
-}
-
 static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
 				struct nameidata *nd)
 {
 	struct dentry *ret = NULL;
-	struct sysfs_dirent * parent_sd = dentry->d_parent->d_fsdata;
-	struct sysfs_dirent * sd;
-	struct bin_attribute *bin_attr;
+	struct sysfs_dirent *parent_sd = dentry->d_parent->d_fsdata;
+	struct sysfs_dirent *sd;
 	struct inode *inode;
-	int found = 0;
 
 	mutex_lock(&sysfs_mutex);
 
-	for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) {
-		if (sysfs_type(sd) &&
-		    !strcmp(sd->s_name, dentry->d_name.name)) {
-			found = 1;
-			break;
-		}
-	}
+	sd = sysfs_find_dirent(parent_sd, dentry->d_name.name);
 
 	/* no such entry */
-	if (!found)
+	if (!sd)
 		goto out_unlock;
 
 	/* attach dentry and inode */
@@ -790,33 +689,11 @@
 		goto out_unlock;
 	}
 
-	if (inode->i_state & I_NEW) {
-		/* initialize inode according to type */
-		switch (sysfs_type(sd)) {
-		case SYSFS_DIR:
-			inode->i_op = &sysfs_dir_inode_operations;
-			inode->i_fop = &sysfs_dir_operations;
-			inode->i_nlink = sysfs_count_nlink(sd);
-			break;
-		case SYSFS_KOBJ_ATTR:
-			inode->i_size = PAGE_SIZE;
-			inode->i_fop = &sysfs_file_operations;
-			break;
-		case SYSFS_KOBJ_BIN_ATTR:
-			bin_attr = sd->s_elem.bin_attr.bin_attr;
-			inode->i_size = bin_attr->size;
-			inode->i_fop = &bin_fops;
-			break;
-		case SYSFS_KOBJ_LINK:
-			inode->i_op = &sysfs_symlink_inode_operations;
-			break;
-		default:
-			BUG();
-		}
-	}
-
-	sysfs_instantiate(dentry, inode);
-	sysfs_attach_dentry(sd, dentry);
+	/* instantiate and hash dentry */
+	dentry->d_op = &sysfs_dentry_ops;
+	dentry->d_fsdata = sysfs_get(sd);
+	d_instantiate(dentry, inode);
+	d_rehash(dentry);
 
  out_unlock:
 	mutex_unlock(&sysfs_mutex);
@@ -833,7 +710,6 @@
 	struct sysfs_addrm_cxt acxt;
 
 	sysfs_addrm_start(&acxt, sd->s_parent);
-	sysfs_unlink_sibling(sd);
 	sysfs_remove_one(&acxt, sd);
 	sysfs_addrm_finish(&acxt);
 }
@@ -854,15 +730,13 @@
 
 	pr_debug("sysfs %s: removing dir\n", dir_sd->s_name);
 	sysfs_addrm_start(&acxt, dir_sd);
-	pos = &dir_sd->s_children;
+	pos = &dir_sd->s_dir.children;
 	while (*pos) {
 		struct sysfs_dirent *sd = *pos;
 
-		if (sysfs_type(sd) && sysfs_type(sd) != SYSFS_DIR) {
-			*pos = sd->s_sibling;
-			sd->s_sibling = NULL;
+		if (sysfs_type(sd) != SYSFS_DIR)
 			sysfs_remove_one(&acxt, sd);
-		} else
+		else
 			pos = &(*pos)->s_sibling;
 	}
 	sysfs_addrm_finish(&acxt);
@@ -890,90 +764,68 @@
 	__sysfs_remove_dir(sd);
 }
 
-int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,
-		     const char *new_name)
+int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
 {
 	struct sysfs_dirent *sd = kobj->sd;
-	struct dentry *new_parent = NULL;
+	struct dentry *parent = NULL;
 	struct dentry *old_dentry = NULL, *new_dentry = NULL;
 	const char *dup_name = NULL;
 	int error;
 
-	/* get dentries */
+	mutex_lock(&sysfs_rename_mutex);
+
+	error = 0;
+	if (strcmp(sd->s_name, new_name) == 0)
+		goto out;	/* nothing to rename */
+
+	/* get the original dentry */
 	old_dentry = sysfs_get_dentry(sd);
 	if (IS_ERR(old_dentry)) {
 		error = PTR_ERR(old_dentry);
-		goto out_dput;
+		goto out;
 	}
 
-	new_parent = sysfs_get_dentry(new_parent_sd);
-	if (IS_ERR(new_parent)) {
-		error = PTR_ERR(new_parent);
-		goto out_dput;
-	}
+	parent = old_dentry->d_parent;
 
-	/* lock new_parent and get dentry for new name */
-	mutex_lock(&new_parent->d_inode->i_mutex);
-
-	new_dentry = lookup_one_len(new_name, new_parent, strlen(new_name));
-	if (IS_ERR(new_dentry)) {
-		error = PTR_ERR(new_dentry);
-		goto out_unlock;
-	}
-
-	/* By allowing two different directories with the same
-	 * d_parent we allow this routine to move between different
-	 * shadows of the same directory
-	 */
-	error = -EINVAL;
-	if (old_dentry->d_parent->d_inode != new_parent->d_inode ||
-	    new_dentry->d_parent->d_inode != new_parent->d_inode ||
-	    old_dentry == new_dentry)
-		goto out_unlock;
+	/* lock parent and get dentry for new name */
+	mutex_lock(&parent->d_inode->i_mutex);
+	mutex_lock(&sysfs_mutex);
 
 	error = -EEXIST;
-	if (new_dentry->d_inode)
+	if (sysfs_find_dirent(sd->s_parent, new_name))
+		goto out_unlock;
+
+	error = -ENOMEM;
+	new_dentry = d_alloc_name(parent, new_name);
+	if (!new_dentry)
 		goto out_unlock;
 
 	/* rename kobject and sysfs_dirent */
 	error = -ENOMEM;
 	new_name = dup_name = kstrdup(new_name, GFP_KERNEL);
 	if (!new_name)
-		goto out_drop;
+		goto out_unlock;
 
 	error = kobject_set_name(kobj, "%s", new_name);
 	if (error)
-		goto out_drop;
-
-	mutex_lock(&sysfs_mutex);
+		goto out_unlock;
 
 	dup_name = sd->s_name;
 	sd->s_name = new_name;
 
-	/* move under the new parent */
+	/* rename */
 	d_add(new_dentry, NULL);
-	d_move(sd->s_dentry, new_dentry);
-
-	sysfs_unlink_sibling(sd);
-	sysfs_get(new_parent_sd);
-	sysfs_put(sd->s_parent);
-	sd->s_parent = new_parent_sd;
-	sysfs_link_sibling(sd);
-
-	mutex_unlock(&sysfs_mutex);
+	d_move(old_dentry, new_dentry);
 
 	error = 0;
-	goto out_unlock;
-
- out_drop:
-	d_drop(new_dentry);
  out_unlock:
-	mutex_unlock(&new_parent->d_inode->i_mutex);
- out_dput:
+	mutex_unlock(&sysfs_mutex);
+	mutex_unlock(&parent->d_inode->i_mutex);
 	kfree(dup_name);
-	dput(new_parent);
 	dput(old_dentry);
 	dput(new_dentry);
+ out:
+	mutex_unlock(&sysfs_rename_mutex);
 	return error;
 }
 
@@ -985,96 +837,69 @@
 	struct dentry *old_dentry = NULL, *new_dentry = NULL;
 	int error;
 
+	mutex_lock(&sysfs_rename_mutex);
 	BUG_ON(!sd->s_parent);
 	new_parent_sd = new_parent_kobj->sd ? new_parent_kobj->sd : &sysfs_root;
 
+	error = 0;
+	if (sd->s_parent == new_parent_sd)
+		goto out;	/* nothing to move */
+
 	/* get dentries */
 	old_dentry = sysfs_get_dentry(sd);
 	if (IS_ERR(old_dentry)) {
 		error = PTR_ERR(old_dentry);
-		goto out_dput;
+		goto out;
 	}
-	old_parent = sd->s_parent->s_dentry;
+	old_parent = old_dentry->d_parent;
 
 	new_parent = sysfs_get_dentry(new_parent_sd);
 	if (IS_ERR(new_parent)) {
 		error = PTR_ERR(new_parent);
-		goto out_dput;
+		goto out;
 	}
 
-	if (old_parent->d_inode == new_parent->d_inode) {
-		error = 0;
-		goto out_dput;	/* nothing to move */
-	}
 again:
 	mutex_lock(&old_parent->d_inode->i_mutex);
 	if (!mutex_trylock(&new_parent->d_inode->i_mutex)) {
 		mutex_unlock(&old_parent->d_inode->i_mutex);
 		goto again;
 	}
+	mutex_lock(&sysfs_mutex);
 
-	new_dentry = lookup_one_len(kobj->name, new_parent, strlen(kobj->name));
-	if (IS_ERR(new_dentry)) {
-		error = PTR_ERR(new_dentry);
+	error = -EEXIST;
+	if (sysfs_find_dirent(new_parent_sd, sd->s_name))
 		goto out_unlock;
-	} else
-		error = 0;
+
+	error = -ENOMEM;
+	new_dentry = d_alloc_name(new_parent, sd->s_name);
+	if (!new_dentry)
+		goto out_unlock;
+
+	error = 0;
 	d_add(new_dentry, NULL);
-	d_move(sd->s_dentry, new_dentry);
+	d_move(old_dentry, new_dentry);
 	dput(new_dentry);
 
 	/* Remove from old parent's list and insert into new parent's list. */
-	mutex_lock(&sysfs_mutex);
-
 	sysfs_unlink_sibling(sd);
 	sysfs_get(new_parent_sd);
 	sysfs_put(sd->s_parent);
 	sd->s_parent = new_parent_sd;
 	sysfs_link_sibling(sd);
 
-	mutex_unlock(&sysfs_mutex);
-
  out_unlock:
+	mutex_unlock(&sysfs_mutex);
 	mutex_unlock(&new_parent->d_inode->i_mutex);
 	mutex_unlock(&old_parent->d_inode->i_mutex);
- out_dput:
+ out:
 	dput(new_parent);
 	dput(old_dentry);
 	dput(new_dentry);
+	mutex_unlock(&sysfs_rename_mutex);
 	return error;
 }
 
-static int sysfs_dir_open(struct inode *inode, struct file *file)
-{
-	struct dentry * dentry = file->f_path.dentry;
-	struct sysfs_dirent * parent_sd = dentry->d_fsdata;
-	struct sysfs_dirent * sd;
-
-	sd = sysfs_new_dirent("_DIR_", 0, 0);
-	if (sd) {
-		mutex_lock(&sysfs_mutex);
-		sd->s_parent = sysfs_get(parent_sd);
-		sysfs_link_sibling(sd);
-		mutex_unlock(&sysfs_mutex);
-	}
-
-	file->private_data = sd;
-	return sd ? 0 : -ENOMEM;
-}
-
-static int sysfs_dir_close(struct inode *inode, struct file *file)
-{
-	struct sysfs_dirent * cursor = file->private_data;
-
-	mutex_lock(&sysfs_mutex);
-	sysfs_unlink_sibling(cursor);
-	mutex_unlock(&sysfs_mutex);
-
-	release_sysfs_dirent(cursor);
-
-	return 0;
-}
-
 /* Relationship between s_mode and the DT_xxx types */
 static inline unsigned char dt_type(struct sysfs_dirent *sd)
 {
@@ -1085,232 +910,51 @@
 {
 	struct dentry *dentry = filp->f_path.dentry;
 	struct sysfs_dirent * parent_sd = dentry->d_fsdata;
-	struct sysfs_dirent *cursor = filp->private_data;
-	struct sysfs_dirent **pos;
+	struct sysfs_dirent *pos;
 	ino_t ino;
-	int i = filp->f_pos;
 
-	switch (i) {
-		case 0:
+	if (filp->f_pos == 0) {
+		ino = parent_sd->s_ino;
+		if (filldir(dirent, ".", 1, filp->f_pos, ino, DT_DIR) == 0)
+			filp->f_pos++;
+	}
+	if (filp->f_pos == 1) {
+		if (parent_sd->s_parent)
+			ino = parent_sd->s_parent->s_ino;
+		else
 			ino = parent_sd->s_ino;
-			if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
-				break;
+		if (filldir(dirent, "..", 2, filp->f_pos, ino, DT_DIR) == 0)
 			filp->f_pos++;
-			i++;
-			/* fallthrough */
-		case 1:
-			if (parent_sd->s_parent)
-				ino = parent_sd->s_parent->s_ino;
-			else
-				ino = parent_sd->s_ino;
-			if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0)
-				break;
-			filp->f_pos++;
-			i++;
-			/* fallthrough */
-		default:
-			mutex_lock(&sysfs_mutex);
-
-			pos = &parent_sd->s_children;
-			while (*pos != cursor)
-				pos = &(*pos)->s_sibling;
-
-			/* unlink cursor */
-			*pos = cursor->s_sibling;
-
-			if (filp->f_pos == 2)
-				pos = &parent_sd->s_children;
-
-			for ( ; *pos; pos = &(*pos)->s_sibling) {
-				struct sysfs_dirent *next = *pos;
-				const char * name;
-				int len;
-
-				if (!sysfs_type(next))
-					continue;
-
-				name = next->s_name;
-				len = strlen(name);
-				ino = next->s_ino;
-
-				if (filldir(dirent, name, len, filp->f_pos, ino,
-						 dt_type(next)) < 0)
-					break;
-
-				filp->f_pos++;
-			}
-
-			/* put cursor back in */
-			cursor->s_sibling = *pos;
-			*pos = cursor;
-
-			mutex_unlock(&sysfs_mutex);
 	}
-	return 0;
-}
-
-static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin)
-{
-	struct dentry * dentry = file->f_path.dentry;
-
-	switch (origin) {
-		case 1:
-			offset += file->f_pos;
-		case 0:
-			if (offset >= 0)
-				break;
-		default:
-			return -EINVAL;
-	}
-	if (offset != file->f_pos) {
+	if ((filp->f_pos > 1) && (filp->f_pos < INT_MAX)) {
 		mutex_lock(&sysfs_mutex);
 
-		file->f_pos = offset;
-		if (file->f_pos >= 2) {
-			struct sysfs_dirent *sd = dentry->d_fsdata;
-			struct sysfs_dirent *cursor = file->private_data;
-			struct sysfs_dirent **pos;
-			loff_t n = file->f_pos - 2;
+		/* Skip the dentries we have already reported */
+		pos = parent_sd->s_dir.children;
+		while (pos && (filp->f_pos > pos->s_ino))
+			pos = pos->s_sibling;
 
-			sysfs_unlink_sibling(cursor);
+		for ( ; pos; pos = pos->s_sibling) {
+			const char * name;
+			int len;
 
-			pos = &sd->s_children;
-			while (n && *pos) {
-				struct sysfs_dirent *next = *pos;
-				if (sysfs_type(next))
-					n--;
-				pos = &(*pos)->s_sibling;
-			}
+			name = pos->s_name;
+			len = strlen(name);
+			filp->f_pos = ino = pos->s_ino;
 
-			cursor->s_sibling = *pos;
-			*pos = cursor;
+			if (filldir(dirent, name, len, filp->f_pos, ino,
+					 dt_type(pos)) < 0)
+				break;
 		}
-
+		if (!pos)
+			filp->f_pos = INT_MAX;
 		mutex_unlock(&sysfs_mutex);
 	}
-
-	return offset;
-}
-
-
-/**
- *	sysfs_make_shadowed_dir - Setup so a directory can be shadowed
- *	@kobj:	object we're creating shadow of.
- */
-
-int sysfs_make_shadowed_dir(struct kobject *kobj,
-	void * (*follow_link)(struct dentry *, struct nameidata *))
-{
-	struct dentry *dentry;
-	struct inode *inode;
-	struct inode_operations *i_op;
-
-	/* get dentry for @kobj->sd, dentry of a shadowed dir is pinned */
-	dentry = sysfs_get_dentry(kobj->sd);
-	if (IS_ERR(dentry))
-		return PTR_ERR(dentry);
-
-	inode = dentry->d_inode;
-	if (inode->i_op != &sysfs_dir_inode_operations) {
-		dput(dentry);
-		return -EINVAL;
-	}
-
-	i_op = kmalloc(sizeof(*i_op), GFP_KERNEL);
-	if (!i_op)
-		return -ENOMEM;
-
-	memcpy(i_op, &sysfs_dir_inode_operations, sizeof(*i_op));
-	i_op->follow_link = follow_link;
-
-	/* Locking of inode->i_op?
-	 * Since setting i_op is a single word write and they
-	 * are atomic we should be ok here.
-	 */
-	inode->i_op = i_op;
 	return 0;
 }
 
-/**
- *	sysfs_create_shadow_dir - create a shadow directory for an object.
- *	@kobj:	object we're creating directory for.
- *
- *	sysfs_make_shadowed_dir must already have been called on this
- *	directory.
- */
-
-struct sysfs_dirent *sysfs_create_shadow_dir(struct kobject *kobj)
-{
-	struct sysfs_dirent *parent_sd = kobj->sd->s_parent;
-	struct dentry *dir, *parent, *shadow;
-	struct inode *inode;
-	struct sysfs_dirent *sd;
-	struct sysfs_addrm_cxt acxt;
-
-	dir = sysfs_get_dentry(kobj->sd);
-	if (IS_ERR(dir)) {
-		sd = (void *)dir;
-		goto out;
-	}
-	parent = dir->d_parent;
-
-	inode = dir->d_inode;
-	sd = ERR_PTR(-EINVAL);
-	if (!sysfs_is_shadowed_inode(inode))
-		goto out_dput;
-
-	shadow = d_alloc(parent, &dir->d_name);
-	if (!shadow)
-		goto nomem;
-
-	sd = sysfs_new_dirent("_SHADOW_", inode->i_mode, SYSFS_DIR);
-	if (!sd)
-		goto nomem;
-	sd->s_elem.dir.kobj = kobj;
-
-	sysfs_addrm_start(&acxt, parent_sd);
-
-	/* add but don't link into children list */
-	sysfs_add_one(&acxt, sd);
-
-	/* attach and instantiate dentry */
-	sysfs_attach_dentry(sd, shadow);
-	d_instantiate(shadow, igrab(inode));
-	inc_nlink(inode);	/* tj: synchronization? */
-
-	sysfs_addrm_finish(&acxt);
-
-	dget(shadow);		/* Extra count - pin the dentry in core */
-
-	goto out_dput;
-
- nomem:
-	dput(shadow);
-	sd = ERR_PTR(-ENOMEM);
- out_dput:
-	dput(dir);
- out:
-	return sd;
-}
-
-/**
- *	sysfs_remove_shadow_dir - remove an object's directory.
- *	@shadow_sd: sysfs_dirent of shadow directory
- *
- *	The only thing special about this is that we remove any files in
- *	the directory before we remove the directory, and we've inlined
- *	what used to be sysfs_rmdir() below, instead of calling separately.
- */
-
-void sysfs_remove_shadow_dir(struct sysfs_dirent *shadow_sd)
-{
-	__sysfs_remove_dir(shadow_sd);
-}
 
 const struct file_operations sysfs_dir_operations = {
-	.open		= sysfs_dir_open,
-	.release	= sysfs_dir_close,
-	.llseek		= sysfs_dir_lseek,
 	.read		= generic_read_dir,
 	.readdir	= sysfs_readdir,
 };
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index 3e1cc06..d3be1e7 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -1,15 +1,22 @@
 /*
- * file.c - operations for regular (text) files.
+ * fs/sysfs/file.c - sysfs regular (text) file implementation
+ *
+ * Copyright (c) 2001-3 Patrick Mochel
+ * Copyright (c) 2007 SUSE Linux Products GmbH
+ * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
+ *
+ * This file is released under the GPLv2.
+ *
+ * Please see Documentation/filesystems/sysfs.txt for more information.
  */
 
 #include <linux/module.h>
-#include <linux/fsnotify.h>
 #include <linux/kobject.h>
 #include <linux/namei.h>
 #include <linux/poll.h>
 #include <linux/list.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
-#include <asm/semaphore.h>
 
 #include "sysfs.h"
 
@@ -50,14 +57,33 @@
 	.store	= subsys_attr_store,
 };
 
+/*
+ * There's one sysfs_buffer for each open file and one
+ * sysfs_open_dirent for each sysfs_dirent with one or more open
+ * files.
+ *
+ * filp->private_data points to sysfs_buffer and
+ * sysfs_dirent->s_attr.open points to sysfs_open_dirent.  s_attr.open
+ * is protected by sysfs_open_dirent_lock.
+ */
+static spinlock_t sysfs_open_dirent_lock = SPIN_LOCK_UNLOCKED;
+
+struct sysfs_open_dirent {
+	atomic_t		refcnt;
+	atomic_t		event;
+	wait_queue_head_t	poll;
+	struct list_head	buffers; /* goes through sysfs_buffer.list */
+};
+
 struct sysfs_buffer {
 	size_t			count;
 	loff_t			pos;
 	char			* page;
 	struct sysfs_ops	* ops;
-	struct semaphore	sem;
+	struct mutex		mutex;
 	int			needs_read_fill;
 	int			event;
+	struct list_head	list;
 };
 
 /**
@@ -74,7 +100,7 @@
 static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer)
 {
 	struct sysfs_dirent *attr_sd = dentry->d_fsdata;
-	struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
+	struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
 	struct sysfs_ops * ops = buffer->ops;
 	int ret = 0;
 	ssize_t count;
@@ -88,8 +114,8 @@
 	if (!sysfs_get_active_two(attr_sd))
 		return -ENODEV;
 
-	buffer->event = atomic_read(&attr_sd->s_event);
-	count = ops->show(kobj, attr_sd->s_elem.attr.attr, buffer->page);
+	buffer->event = atomic_read(&attr_sd->s_attr.open->event);
+	count = ops->show(kobj, attr_sd->s_attr.attr, buffer->page);
 
 	sysfs_put_active_two(attr_sd);
 
@@ -128,7 +154,7 @@
 	struct sysfs_buffer * buffer = file->private_data;
 	ssize_t retval = 0;
 
-	down(&buffer->sem);
+	mutex_lock(&buffer->mutex);
 	if (buffer->needs_read_fill) {
 		retval = fill_read_buffer(file->f_path.dentry,buffer);
 		if (retval)
@@ -139,7 +165,7 @@
 	retval = simple_read_from_buffer(buf, count, ppos, buffer->page,
 					 buffer->count);
 out:
-	up(&buffer->sem);
+	mutex_unlock(&buffer->mutex);
 	return retval;
 }
 
@@ -189,7 +215,7 @@
 flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t count)
 {
 	struct sysfs_dirent *attr_sd = dentry->d_fsdata;
-	struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
+	struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
 	struct sysfs_ops * ops = buffer->ops;
 	int rc;
 
@@ -197,7 +223,7 @@
 	if (!sysfs_get_active_two(attr_sd))
 		return -ENODEV;
 
-	rc = ops->store(kobj, attr_sd->s_elem.attr.attr, buffer->page, count);
+	rc = ops->store(kobj, attr_sd->s_attr.attr, buffer->page, count);
 
 	sysfs_put_active_two(attr_sd);
 
@@ -228,20 +254,102 @@
 	struct sysfs_buffer * buffer = file->private_data;
 	ssize_t len;
 
-	down(&buffer->sem);
+	mutex_lock(&buffer->mutex);
 	len = fill_write_buffer(buffer, buf, count);
 	if (len > 0)
 		len = flush_write_buffer(file->f_path.dentry, buffer, len);
 	if (len > 0)
 		*ppos += len;
-	up(&buffer->sem);
+	mutex_unlock(&buffer->mutex);
 	return len;
 }
 
+/**
+ *	sysfs_get_open_dirent - get or create sysfs_open_dirent
+ *	@sd: target sysfs_dirent
+ *	@buffer: sysfs_buffer for this instance of open
+ *
+ *	If @sd->s_attr.open exists, increment its reference count;
+ *	otherwise, create one.  @buffer is chained to the buffers
+ *	list.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno on failure.
+ */
+static int sysfs_get_open_dirent(struct sysfs_dirent *sd,
+				 struct sysfs_buffer *buffer)
+{
+	struct sysfs_open_dirent *od, *new_od = NULL;
+
+ retry:
+	spin_lock(&sysfs_open_dirent_lock);
+
+	if (!sd->s_attr.open && new_od) {
+		sd->s_attr.open = new_od;
+		new_od = NULL;
+	}
+
+	od = sd->s_attr.open;
+	if (od) {
+		atomic_inc(&od->refcnt);
+		list_add_tail(&buffer->list, &od->buffers);
+	}
+
+	spin_unlock(&sysfs_open_dirent_lock);
+
+	if (od) {
+		kfree(new_od);
+		return 0;
+	}
+
+	/* not there, initialize a new one and retry */
+	new_od = kmalloc(sizeof(*new_od), GFP_KERNEL);
+	if (!new_od)
+		return -ENOMEM;
+
+	atomic_set(&new_od->refcnt, 0);
+	atomic_set(&new_od->event, 1);
+	init_waitqueue_head(&new_od->poll);
+	INIT_LIST_HEAD(&new_od->buffers);
+	goto retry;
+}
+
+/**
+ *	sysfs_put_open_dirent - put sysfs_open_dirent
+ *	@sd: target sysfs_dirent
+ *	@buffer: associated sysfs_buffer
+ *
+ *	Put @sd->s_attr.open and unlink @buffer from the buffers list.
+ *	If reference count reaches zero, disassociate and free it.
+ *
+ *	LOCKING:
+ *	None.
+ */
+static void sysfs_put_open_dirent(struct sysfs_dirent *sd,
+				  struct sysfs_buffer *buffer)
+{
+	struct sysfs_open_dirent *od = sd->s_attr.open;
+
+	spin_lock(&sysfs_open_dirent_lock);
+
+	list_del(&buffer->list);
+	if (atomic_dec_and_test(&od->refcnt))
+		sd->s_attr.open = NULL;
+	else
+		od = NULL;
+
+	spin_unlock(&sysfs_open_dirent_lock);
+
+	kfree(od);
+}
+
 static int sysfs_open_file(struct inode *inode, struct file *file)
 {
 	struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
-	struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
+	struct kobject *kobj = attr_sd->s_parent->s_dir.kobj;
 	struct sysfs_buffer * buffer;
 	struct sysfs_ops * ops = NULL;
 	int error;
@@ -294,33 +402,38 @@
 	if (!buffer)
 		goto err_out;
 
-	init_MUTEX(&buffer->sem);
+	mutex_init(&buffer->mutex);
 	buffer->needs_read_fill = 1;
 	buffer->ops = ops;
 	file->private_data = buffer;
 
-	/* open succeeded, put active references and pin attr_sd */
+	/* make sure we have open dirent struct */
+	error = sysfs_get_open_dirent(attr_sd, buffer);
+	if (error)
+		goto err_free;
+
+	/* open succeeded, put active references */
 	sysfs_put_active_two(attr_sd);
-	sysfs_get(attr_sd);
 	return 0;
 
+ err_free:
+	kfree(buffer);
  err_out:
 	sysfs_put_active_two(attr_sd);
 	return error;
 }
 
-static int sysfs_release(struct inode * inode, struct file * filp)
+static int sysfs_release(struct inode *inode, struct file *filp)
 {
-	struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata;
+	struct sysfs_dirent *sd = filp->f_path.dentry->d_fsdata;
 	struct sysfs_buffer *buffer = filp->private_data;
 
-	sysfs_put(attr_sd);
+	sysfs_put_open_dirent(sd, buffer);
 
-	if (buffer) {
-		if (buffer->page)
-			free_page((unsigned long)buffer->page);
-		kfree(buffer);
-	}
+	if (buffer->page)
+		free_page((unsigned long)buffer->page);
+	kfree(buffer);
+
 	return 0;
 }
 
@@ -335,24 +448,24 @@
  * again will not get new data, or reset the state of 'poll'.
  * Reminder: this only works for attributes which actively support
  * it, and it is not possible to test an attribute from userspace
- * to see if it supports poll (Nether 'poll' or 'select' return
+ * to see if it supports poll (Neither 'poll' nor 'select' return
  * an appropriate error code).  When in doubt, set a suitable timeout value.
  */
 static unsigned int sysfs_poll(struct file *filp, poll_table *wait)
 {
 	struct sysfs_buffer * buffer = filp->private_data;
 	struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata;
-	struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
+	struct sysfs_open_dirent *od = attr_sd->s_attr.open;
 
 	/* need parent for the kobj, grab both */
 	if (!sysfs_get_active_two(attr_sd))
 		goto trigger;
 
-	poll_wait(filp, &kobj->poll, wait);
+	poll_wait(filp, &od->poll, wait);
 
 	sysfs_put_active_two(attr_sd);
 
-	if (buffer->event != atomic_read(&attr_sd->s_event))
+	if (buffer->event != atomic_read(&od->event))
 		goto trigger;
 
 	return 0;
@@ -373,8 +486,17 @@
 	if (sd && attr)
 		sd = sysfs_find_dirent(sd, attr);
 	if (sd) {
-		atomic_inc(&sd->s_event);
-		wake_up_interruptible(&k->poll);
+		struct sysfs_open_dirent *od;
+
+		spin_lock(&sysfs_open_dirent_lock);
+
+		od = sd->s_attr.open;
+		if (od) {
+			atomic_inc(&od->event);
+			wake_up_interruptible(&od->poll);
+		}
+
+		spin_unlock(&sysfs_open_dirent_lock);
 	}
 
 	mutex_unlock(&sysfs_mutex);
@@ -397,25 +519,21 @@
 	umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG;
 	struct sysfs_addrm_cxt acxt;
 	struct sysfs_dirent *sd;
+	int rc;
 
 	sd = sysfs_new_dirent(attr->name, mode, type);
 	if (!sd)
 		return -ENOMEM;
-	sd->s_elem.attr.attr = (void *)attr;
+	sd->s_attr.attr = (void *)attr;
 
 	sysfs_addrm_start(&acxt, dir_sd);
+	rc = sysfs_add_one(&acxt, sd);
+	sysfs_addrm_finish(&acxt);
 
-	if (!sysfs_find_dirent(dir_sd, attr->name)) {
-		sysfs_add_one(&acxt, sd);
-		sysfs_link_sibling(sd);
-	}
-
-	if (!sysfs_addrm_finish(&acxt)) {
+	if (rc)
 		sysfs_put(sd);
-		return -EEXIST;
-	}
 
-	return 0;
+	return rc;
 }
 
 
@@ -457,42 +575,6 @@
 }
 EXPORT_SYMBOL_GPL(sysfs_add_file_to_group);
 
-
-/**
- * sysfs_update_file - update the modified timestamp on an object attribute.
- * @kobj: object we're acting for.
- * @attr: attribute descriptor.
- */
-int sysfs_update_file(struct kobject * kobj, const struct attribute * attr)
-{
-	struct sysfs_dirent *victim_sd = NULL;
-	struct dentry *victim = NULL;
-	int rc;
-
-	rc = -ENOENT;
-	victim_sd = sysfs_get_dirent(kobj->sd, attr->name);
-	if (!victim_sd)
-		goto out;
-
-	victim = sysfs_get_dentry(victim_sd);
-	if (IS_ERR(victim)) {
-		rc = PTR_ERR(victim);
-		victim = NULL;
-		goto out;
-	}
-
-	mutex_lock(&victim->d_inode->i_mutex);
-	victim->d_inode->i_mtime = CURRENT_TIME;
-	fsnotify_modify(victim);
-	mutex_unlock(&victim->d_inode->i_mutex);
-	rc = 0;
- out:
-	dput(victim);
-	sysfs_put(victim_sd);
-	return rc;
-}
-
-
 /**
  * sysfs_chmod_file - update the modified mode value on an object attribute.
  * @kobj: object we're acting for.
@@ -513,7 +595,9 @@
 	if (!victim_sd)
 		goto out;
 
+	mutex_lock(&sysfs_rename_mutex);
 	victim = sysfs_get_dentry(victim_sd);
+	mutex_unlock(&sysfs_rename_mutex);
 	if (IS_ERR(victim)) {
 		rc = PTR_ERR(victim);
 		victim = NULL;
@@ -521,10 +605,19 @@
 	}
 
 	inode = victim->d_inode;
+
 	mutex_lock(&inode->i_mutex);
+
 	newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
 	newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
 	rc = notify_change(victim, &newattrs);
+
+	if (rc == 0) {
+		mutex_lock(&sysfs_mutex);
+		victim_sd->s_mode = newattrs.ia_mode;
+		mutex_unlock(&sysfs_mutex);
+	}
+
 	mutex_unlock(&inode->i_mutex);
  out:
 	dput(victim);
@@ -632,4 +725,3 @@
 
 EXPORT_SYMBOL_GPL(sysfs_create_file);
 EXPORT_SYMBOL_GPL(sysfs_remove_file);
-EXPORT_SYMBOL_GPL(sysfs_update_file);
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
index f318b73..d197237 100644
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -13,8 +13,6 @@
 #include <linux/dcache.h>
 #include <linux/namei.h>
 #include <linux/err.h>
-#include <linux/fs.h>
-#include <asm/semaphore.h>
 #include "sysfs.h"
 
 
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index 10d1b52..9236635 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -1,7 +1,11 @@
 /*
- * inode.c - basic inode and dentry operations.
+ * fs/sysfs/inode.c - basic sysfs inode and dentry operations
  *
- * sysfs is Copyright (c) 2001-3 Patrick Mochel
+ * Copyright (c) 2001-3 Patrick Mochel
+ * Copyright (c) 2007 SUSE Linux Products GmbH
+ * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
+ *
+ * This file is released under the GPLv2.
  *
  * Please see Documentation/filesystems/sysfs.txt for more information.
  */
@@ -14,7 +18,6 @@
 #include <linux/capability.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
-#include <asm/semaphore.h>
 #include "sysfs.h"
 
 extern struct super_block * sysfs_sb;
@@ -34,16 +37,6 @@
 	.setattr	= sysfs_setattr,
 };
 
-void sysfs_delete_inode(struct inode *inode)
-{
-	/* Free the shadowed directory inode operations */
-	if (sysfs_is_shadowed_inode(inode)) {
-		kfree(inode->i_op);
-		inode->i_op = NULL;
-	}
-	return generic_delete_inode(inode);
-}
-
 int sysfs_setattr(struct dentry * dentry, struct iattr * iattr)
 {
 	struct inode * inode = dentry->d_inode;
@@ -133,8 +126,22 @@
  */
 static struct lock_class_key sysfs_inode_imutex_key;
 
+static int sysfs_count_nlink(struct sysfs_dirent *sd)
+{
+	struct sysfs_dirent *child;
+	int nr = 0;
+
+	for (child = sd->s_dir.children; child; child = child->s_sibling)
+		if (sysfs_type(child) == SYSFS_DIR)
+			nr++;
+
+	return nr + 2;
+}
+
 static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
 {
+	struct bin_attribute *bin_attr;
+
 	inode->i_blocks = 0;
 	inode->i_mapping->a_ops = &sysfs_aops;
 	inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;
@@ -150,6 +157,32 @@
 		set_inode_attr(inode, sd->s_iattr);
 	} else
 		set_default_inode_attr(inode, sd->s_mode);
+
+
+	/* initialize inode according to type */
+	switch (sysfs_type(sd)) {
+	case SYSFS_DIR:
+		inode->i_op = &sysfs_dir_inode_operations;
+		inode->i_fop = &sysfs_dir_operations;
+		inode->i_nlink = sysfs_count_nlink(sd);
+		break;
+	case SYSFS_KOBJ_ATTR:
+		inode->i_size = PAGE_SIZE;
+		inode->i_fop = &sysfs_file_operations;
+		break;
+	case SYSFS_KOBJ_BIN_ATTR:
+		bin_attr = sd->s_bin_attr.bin_attr;
+		inode->i_size = bin_attr->size;
+		inode->i_fop = &bin_fops;
+		break;
+	case SYSFS_KOBJ_LINK:
+		inode->i_op = &sysfs_symlink_inode_operations;
+		break;
+	default:
+		BUG();
+	}
+
+	unlock_new_inode(inode);
 }
 
 /**
@@ -177,50 +210,24 @@
 	return inode;
 }
 
-/**
- *	sysfs_instantiate - instantiate dentry
- *	@dentry: dentry to be instantiated
- *	@inode: inode associated with @sd
- *
- *	Unlock @inode if locked and instantiate @dentry with @inode.
- *
- *	LOCKING:
- *	None.
- */
-void sysfs_instantiate(struct dentry *dentry, struct inode *inode)
-{
-	BUG_ON(!dentry || dentry->d_inode);
-
-	if (inode->i_state & I_NEW)
-		unlock_new_inode(inode);
-
-	d_instantiate(dentry, inode);
-}
-
 int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name)
 {
 	struct sysfs_addrm_cxt acxt;
-	struct sysfs_dirent **pos, *sd;
+	struct sysfs_dirent *sd;
 
 	if (!dir_sd)
 		return -ENOENT;
 
 	sysfs_addrm_start(&acxt, dir_sd);
 
-	for (pos = &dir_sd->s_children; *pos; pos = &(*pos)->s_sibling) {
-		sd = *pos;
+	sd = sysfs_find_dirent(dir_sd, name);
+	if (sd)
+		sysfs_remove_one(&acxt, sd);
 
-		if (!sysfs_type(sd))
-			continue;
-		if (!strcmp(sd->s_name, name)) {
-			*pos = sd->s_sibling;
-			sd->s_sibling = NULL;
-			sysfs_remove_one(&acxt, sd);
-			break;
-		}
-	}
+	sysfs_addrm_finish(&acxt);
 
-	if (sysfs_addrm_finish(&acxt))
+	if (sd)
 		return 0;
-	return -ENOENT;
+	else
+		return -ENOENT;
 }
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index fbc7b65..c76c540 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -1,5 +1,13 @@
 /*
- * mount.c - operations for initializing and mounting sysfs.
+ * fs/sysfs/symlink.c - operations for initializing and mounting sysfs
+ *
+ * Copyright (c) 2001-3 Patrick Mochel
+ * Copyright (c) 2007 SUSE Linux Products GmbH
+ * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
+ *
+ * This file is released under the GPLv2.
+ *
+ * Please see Documentation/filesystems/sysfs.txt for more information.
  */
 
 #define DEBUG 
@@ -8,25 +16,25 @@
 #include <linux/mount.h>
 #include <linux/pagemap.h>
 #include <linux/init.h>
-#include <asm/semaphore.h>
 
 #include "sysfs.h"
 
 /* Random magic number */
 #define SYSFS_MAGIC 0x62656572
 
-struct vfsmount *sysfs_mount;
+static struct vfsmount *sysfs_mount;
 struct super_block * sysfs_sb = NULL;
 struct kmem_cache *sysfs_dir_cachep;
 
 static const struct super_operations sysfs_ops = {
 	.statfs		= simple_statfs,
-	.drop_inode	= sysfs_delete_inode,
+	.drop_inode	= generic_delete_inode,
 };
 
 struct sysfs_dirent sysfs_root = {
+	.s_name		= "",
 	.s_count	= ATOMIC_INIT(1),
-	.s_flags	= SYSFS_ROOT,
+	.s_flags	= SYSFS_DIR,
 	.s_mode		= S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
 	.s_ino		= 1,
 };
@@ -50,11 +58,6 @@
 		return -ENOMEM;
 	}
 
-	inode->i_op = &sysfs_dir_inode_operations;
-	inode->i_fop = &sysfs_dir_operations;
-	inc_nlink(inode); /* directory, account for "." */
-	unlock_new_inode(inode);
-
 	/* instantiate and link root dentry */
 	root = d_alloc_root(inode);
 	if (!root) {
@@ -62,7 +65,6 @@
 		iput(inode);
 		return -ENOMEM;
 	}
-	sysfs_root.s_dentry = root;
 	root->d_fsdata = &sysfs_root;
 	sb->s_root = root;
 	return 0;
@@ -77,7 +79,7 @@
 static struct file_system_type sysfs_fs_type = {
 	.name		= "sysfs",
 	.get_sb		= sysfs_get_sb,
-	.kill_sb	= kill_litter_super,
+	.kill_sb	= kill_anon_super,
 };
 
 int __init sysfs_init(void)
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c
index 4ce687f..3eac20c 100644
--- a/fs/sysfs/symlink.c
+++ b/fs/sysfs/symlink.c
@@ -1,5 +1,13 @@
 /*
- * symlink.c - operations for sysfs symlinks.
+ * fs/sysfs/symlink.c - sysfs symlink implementation
+ *
+ * Copyright (c) 2001-3 Patrick Mochel
+ * Copyright (c) 2007 SUSE Linux Products GmbH
+ * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
+ *
+ * This file is released under the GPLv2.
+ *
+ * Please see Documentation/filesystems/sysfs.txt for more information.
  */
 
 #include <linux/fs.h>
@@ -7,7 +15,7 @@
 #include <linux/module.h>
 #include <linux/kobject.h>
 #include <linux/namei.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 
 #include "sysfs.h"
 
@@ -60,10 +68,9 @@
 
 	BUG_ON(!name);
 
-	if (!kobj) {
-		if (sysfs_mount && sysfs_mount->mnt_sb)
-			parent_sd = sysfs_mount->mnt_sb->s_root->d_fsdata;
-	} else
+	if (!kobj)
+		parent_sd = &sysfs_root;
+	else
 		parent_sd = kobj->sd;
 
 	error = -EFAULT;
@@ -87,20 +94,15 @@
 	if (!sd)
 		goto out_put;
 
-	sd->s_elem.symlink.target_sd = target_sd;
+	sd->s_symlink.target_sd = target_sd;
 	target_sd = NULL;	/* reference is now owned by the symlink */
 
 	sysfs_addrm_start(&acxt, parent_sd);
+	error = sysfs_add_one(&acxt, sd);
+	sysfs_addrm_finish(&acxt);
 
-	if (!sysfs_find_dirent(parent_sd, name)) {
-		sysfs_add_one(&acxt, sd);
-		sysfs_link_sibling(sd);
-	}
-
-	if (!sysfs_addrm_finish(&acxt)) {
-		error = -EEXIST;
+	if (error)
 		goto out_put;
-	}
 
 	return 0;
 
@@ -148,7 +150,7 @@
 {
 	struct sysfs_dirent *sd = dentry->d_fsdata;
 	struct sysfs_dirent *parent_sd = sd->s_parent;
-	struct sysfs_dirent *target_sd = sd->s_elem.symlink.target_sd;
+	struct sysfs_dirent *target_sd = sd->s_symlink.target_sd;
 	int error;
 
 	mutex_lock(&sysfs_mutex);
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index 6b8c8d7..f0326f2 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -1,20 +1,39 @@
+/*
+ * fs/sysfs/sysfs.h - sysfs internal header file
+ *
+ * Copyright (c) 2001-3 Patrick Mochel
+ * Copyright (c) 2007 SUSE Linux Products GmbH
+ * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
+ *
+ * This file is released under the GPLv2.
+ */
+
+struct sysfs_open_dirent;
+
+/* type-specific structures for sysfs_dirent->s_* union members */
 struct sysfs_elem_dir {
-	struct kobject		* kobj;
+	struct kobject		*kobj;
+	/* children list starts here and goes through sd->s_sibling */
+	struct sysfs_dirent	*children;
 };
 
 struct sysfs_elem_symlink {
-	struct sysfs_dirent	* target_sd;
+	struct sysfs_dirent	*target_sd;
 };
 
 struct sysfs_elem_attr {
-	struct attribute	* attr;
+	struct attribute	*attr;
+	struct sysfs_open_dirent *open;
 };
 
 struct sysfs_elem_bin_attr {
-	struct bin_attribute	* bin_attr;
+	struct bin_attribute	*bin_attr;
 };
 
 /*
+ * sysfs_dirent - the building block of sysfs hierarchy.  Each and
+ * every sysfs node is represented by single sysfs_dirent.
+ *
  * As long as s_count reference is held, the sysfs_dirent itself is
  * accessible.  Dereferencing s_elem or any other outer entity
  * requires s_active reference.
@@ -22,28 +41,43 @@
 struct sysfs_dirent {
 	atomic_t		s_count;
 	atomic_t		s_active;
-	struct sysfs_dirent	* s_parent;
-	struct sysfs_dirent	* s_sibling;
-	struct sysfs_dirent	* s_children;
-	const char		* s_name;
+	struct sysfs_dirent	*s_parent;
+	struct sysfs_dirent	*s_sibling;
+	const char		*s_name;
 
 	union {
-		struct sysfs_elem_dir		dir;
-		struct sysfs_elem_symlink	symlink;
-		struct sysfs_elem_attr		attr;
-		struct sysfs_elem_bin_attr	bin_attr;
-	}			s_elem;
+		struct sysfs_elem_dir		s_dir;
+		struct sysfs_elem_symlink	s_symlink;
+		struct sysfs_elem_attr		s_attr;
+		struct sysfs_elem_bin_attr	s_bin_attr;
+	};
 
 	unsigned int		s_flags;
-	umode_t			s_mode;
 	ino_t			s_ino;
-	struct dentry		* s_dentry;
-	struct iattr		* s_iattr;
-	atomic_t		s_event;
+	umode_t			s_mode;
+	struct iattr		*s_iattr;
 };
 
-#define SD_DEACTIVATED_BIAS	INT_MIN
+#define SD_DEACTIVATED_BIAS		INT_MIN
 
+#define SYSFS_TYPE_MASK			0x00ff
+#define SYSFS_DIR			0x0001
+#define SYSFS_KOBJ_ATTR			0x0002
+#define SYSFS_KOBJ_BIN_ATTR		0x0004
+#define SYSFS_KOBJ_LINK			0x0008
+#define SYSFS_COPY_NAME			(SYSFS_DIR | SYSFS_KOBJ_LINK)
+
+#define SYSFS_FLAG_MASK			~SYSFS_TYPE_MASK
+#define SYSFS_FLAG_REMOVED		0x0200
+
+static inline unsigned int sysfs_type(struct sysfs_dirent *sd)
+{
+	return sd->s_flags & SYSFS_TYPE_MASK;
+}
+
+/*
+ * Context structure to be used while adding/removing nodes.
+ */
 struct sysfs_addrm_cxt {
 	struct sysfs_dirent	*parent_sd;
 	struct inode		*parent_inode;
@@ -51,63 +85,47 @@
 	int			cnt;
 };
 
-extern struct vfsmount * sysfs_mount;
+/*
+ * mount.c
+ */
 extern struct sysfs_dirent sysfs_root;
+extern struct super_block *sysfs_sb;
 extern struct kmem_cache *sysfs_dir_cachep;
 
-extern struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd);
-extern void sysfs_link_sibling(struct sysfs_dirent *sd);
-extern void sysfs_unlink_sibling(struct sysfs_dirent *sd);
-extern struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd);
-extern void sysfs_put_active(struct sysfs_dirent *sd);
-extern struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd);
-extern void sysfs_put_active_two(struct sysfs_dirent *sd);
-extern void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt,
-			      struct sysfs_dirent *parent_sd);
-extern void sysfs_add_one(struct sysfs_addrm_cxt *acxt,
-			  struct sysfs_dirent *sd);
-extern void sysfs_remove_one(struct sysfs_addrm_cxt *acxt,
-			     struct sysfs_dirent *sd);
-extern int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt);
-
-extern void sysfs_delete_inode(struct inode *inode);
-extern struct inode * sysfs_get_inode(struct sysfs_dirent *sd);
-extern void sysfs_instantiate(struct dentry *dentry, struct inode *inode);
-
-extern void release_sysfs_dirent(struct sysfs_dirent * sd);
-extern struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
-					      const unsigned char *name);
-extern struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,
-					     const unsigned char *name);
-extern struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode,
-					     int type);
-
-extern int sysfs_add_file(struct sysfs_dirent *dir_sd,
-			  const struct attribute *attr, int type);
-extern int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name);
-extern struct sysfs_dirent *sysfs_find(struct sysfs_dirent *dir, const char * name);
-
-extern int sysfs_create_subdir(struct kobject *kobj, const char *name,
-			       struct sysfs_dirent **p_sd);
-extern void sysfs_remove_subdir(struct sysfs_dirent *sd);
-
-extern int sysfs_setattr(struct dentry *dentry, struct iattr *iattr);
-
-extern spinlock_t sysfs_assoc_lock;
+/*
+ * dir.c
+ */
 extern struct mutex sysfs_mutex;
-extern struct super_block * sysfs_sb;
+extern struct mutex sysfs_rename_mutex;
+extern spinlock_t sysfs_assoc_lock;
+
 extern const struct file_operations sysfs_dir_operations;
-extern const struct file_operations sysfs_file_operations;
-extern const struct file_operations bin_fops;
 extern const struct inode_operations sysfs_dir_inode_operations;
-extern const struct inode_operations sysfs_symlink_inode_operations;
 
-static inline unsigned int sysfs_type(struct sysfs_dirent *sd)
-{
-	return sd->s_flags & SYSFS_TYPE_MASK;
-}
+struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd);
+struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd);
+void sysfs_put_active(struct sysfs_dirent *sd);
+struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd);
+void sysfs_put_active_two(struct sysfs_dirent *sd);
+void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt,
+		       struct sysfs_dirent *parent_sd);
+int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd);
+void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd);
+void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt);
 
-static inline struct sysfs_dirent * sysfs_get(struct sysfs_dirent * sd)
+struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
+				       const unsigned char *name);
+struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,
+				      const unsigned char *name);
+struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type);
+
+void release_sysfs_dirent(struct sysfs_dirent *sd);
+
+int sysfs_create_subdir(struct kobject *kobj, const char *name,
+			struct sysfs_dirent **p_sd);
+void sysfs_remove_subdir(struct sysfs_dirent *sd);
+
+static inline struct sysfs_dirent *sysfs_get(struct sysfs_dirent *sd)
 {
 	if (sd) {
 		WARN_ON(!atomic_read(&sd->s_count));
@@ -116,13 +134,33 @@
 	return sd;
 }
 
-static inline void sysfs_put(struct sysfs_dirent * sd)
+static inline void sysfs_put(struct sysfs_dirent *sd)
 {
 	if (sd && atomic_dec_and_test(&sd->s_count))
 		release_sysfs_dirent(sd);
 }
 
-static inline int sysfs_is_shadowed_inode(struct inode *inode)
-{
-	return S_ISDIR(inode->i_mode) && inode->i_op->follow_link;
-}
+/*
+ * inode.c
+ */
+struct inode *sysfs_get_inode(struct sysfs_dirent *sd);
+int sysfs_setattr(struct dentry *dentry, struct iattr *iattr);
+int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name);
+
+/*
+ * file.c
+ */
+extern const struct file_operations sysfs_file_operations;
+
+int sysfs_add_file(struct sysfs_dirent *dir_sd,
+		   const struct attribute *attr, int type);
+
+/*
+ * bin.c
+ */
+extern const struct file_operations bin_fops;
+
+/*
+ * symlink.c
+ */
+extern const struct inode_operations sysfs_symlink_inode_operations;
diff --git a/include/asm-powerpc/of_device.h b/include/asm-powerpc/of_device.h
index ec2a8a2..93262f2 100644
--- a/include/asm-powerpc/of_device.h
+++ b/include/asm-powerpc/of_device.h
@@ -20,7 +20,7 @@
 extern ssize_t of_device_get_modalias(struct of_device *ofdev,
 					char *str, ssize_t len);
 extern int of_device_uevent(struct device *dev,
-	char **envp, int num_envp, char *buffer, int buffer_size);
+			    struct kobj_uevent_env *env);
 
 /* This is just here during the transition */
 #include <linux/of_device.h>
diff --git a/include/asm-s390/cache.h b/include/asm-s390/cache.h
index cdf431b..9b86681 100644
--- a/include/asm-s390/cache.h
+++ b/include/asm-s390/cache.h
@@ -14,8 +14,6 @@
 #define L1_CACHE_BYTES     256
 #define L1_CACHE_SHIFT     8
 
-#define ARCH_KMALLOC_MINALIGN	8
-
 #define __read_mostly __attribute__((__section__(".data.read_mostly")))
 
 #endif
diff --git a/include/asm-s390/ccwdev.h b/include/asm-s390/ccwdev.h
index 1aeda27..066aa70 100644
--- a/include/asm-s390/ccwdev.h
+++ b/include/asm-s390/ccwdev.h
@@ -67,36 +67,55 @@
 	return NULL;
 }
 
-/* The struct ccw device is our replacement for the globally accessible
- * ioinfo array. ioinfo will mutate into a subchannel device later.
+/**
+ * struct ccw_device - channel attached device
+ * @ccwlock: pointer to device lock
+ * @id: id of this device
+ * @drv: ccw driver for this device
+ * @dev: embedded device structure
+ * @online: online status of device
+ * @handler: interrupt handler
  *
- * Reference: Documentation/s390/driver-model.txt */
+ * @handler is a member of the device rather than the driver since a driver
+ * can have different interrupt handlers for different ccw devices
+ * (multi-subchannel drivers).
+ */
 struct ccw_device {
 	spinlock_t *ccwlock;
+/* private: */
 	struct ccw_device_private *private;	/* cio private information */
-	struct ccw_device_id id;	/* id of this device, driver_info is
-					   set by ccw_find_driver */
-	struct ccw_driver *drv;		/* */
-	struct device dev;		/* */
+/* public: */
+	struct ccw_device_id id;
+	struct ccw_driver *drv;
+	struct device dev;
 	int online;
-	/* This is sick, but a driver can have different interrupt handlers 
-	   for different ccw_devices (multi-subchannel drivers)... */
 	void (*handler) (struct ccw_device *, unsigned long, struct irb *);
 };
 
 
-/* Each ccw driver registers with the ccw root bus */
+/**
+ * struct ccw driver - device driver for channel attached devices
+ * @owner: owning module
+ * @ids: ids supported by this driver
+ * @probe: function called on probe
+ * @remove: function called on remove
+ * @set_online: called when setting device online
+ * @set_offline: called when setting device offline
+ * @notify: notify driver of device state changes
+ * @shutdown: called at device shutdown
+ * @driver: embedded device driver structure
+ * @name: device driver name
+ */
 struct ccw_driver {
-	struct module *owner;		/* for automatic MOD_INC_USE_COUNT   */
-	struct ccw_device_id *ids;	/* probe driver with these devs      */
-	int (*probe) (struct ccw_device *); /* ask driver to probe dev 	     */
+	struct module *owner;
+	struct ccw_device_id *ids;
+	int (*probe) (struct ccw_device *);
 	void (*remove) (struct ccw_device *);
-					/* device is no longer available     */
 	int (*set_online) (struct ccw_device *);
 	int (*set_offline) (struct ccw_device *);
 	int (*notify) (struct ccw_device *, int);
-	struct device_driver driver;	/* higher level structure, don't init
-					   this from your driver	     */
+	void (*shutdown) (struct ccw_device *);
+	struct device_driver driver;
 	char *name;
 };
 
@@ -124,36 +143,10 @@
 /* Allow forced onlining of boxed devices. */
 #define CCWDEV_ALLOW_FORCE              0x0008
 
-/*
- * ccw_device_start()
- *
- *  Start a S/390 channel program. When the interrupt arrives, the
- *  IRQ handler is called, either immediately, delayed (dev-end missing,
- *  or sense required) or never (no IRQ handler registered).
- *  Depending on the action taken, ccw_device_start() returns:  
- *                           0	     - Success
- *			     -EBUSY  - Device busy, or status pending
- *			     -ENODEV - Device not operational
- *                           -EINVAL - Device invalid for operation
- */
 extern int ccw_device_start(struct ccw_device *, struct ccw1 *,
 			    unsigned long, __u8, unsigned long);
-/*
- * ccw_device_start_timeout()
- *
- * This function notifies the device driver if the channel program has not
- * completed during the specified time. If a timeout occurs, the channel
- * program is terminated via xsch(), hsch() or csch().
- */
 extern int ccw_device_start_timeout(struct ccw_device *, struct ccw1 *,
 				    unsigned long, __u8, unsigned long, int);
-/*
- * ccw_device_start_key()
- * ccw_device_start_key_timeout()
- *
- * Same as ccw_device_start() and ccw_device_start_timeout(), except a
- * storage key != default key can be provided for the I/O.
- */
 extern int ccw_device_start_key(struct ccw_device *, struct ccw1 *,
 				unsigned long, __u8, __u8, unsigned long);
 extern int ccw_device_start_timeout_key(struct ccw_device *, struct ccw1 *,
diff --git a/include/asm-s390/ccwgroup.h b/include/asm-s390/ccwgroup.h
index 925b3dd..7109c7c 100644
--- a/include/asm-s390/ccwgroup.h
+++ b/include/asm-s390/ccwgroup.h
@@ -4,19 +4,41 @@
 struct ccw_device;
 struct ccw_driver;
 
+/**
+ * struct ccwgroup_device - ccw group device
+ * @creator_id: unique number of the driver
+ * @state: online/offline state
+ * @count: number of attached slave devices
+ * @dev: embedded device structure
+ * @cdev: variable number of slave devices, allocated as needed
+ */
 struct ccwgroup_device {
-	unsigned long creator_id;	/* unique number of the driver */
+	unsigned long creator_id;
 	enum {
 		CCWGROUP_OFFLINE,
 		CCWGROUP_ONLINE,
 	} state;
+/* private: */
 	atomic_t onoff;
 	struct mutex reg_mutex;
-	unsigned int count;		/* number of attached slave devices */
-	struct device	dev;		/* master device		    */
-	struct ccw_device *cdev[0];	/* variable number, allocate as needed */
+/* public: */
+	unsigned int count;
+	struct device	dev;
+	struct ccw_device *cdev[0];
 };
 
+/**
+ * struct ccwgroup_driver - driver for ccw group devices
+ * @owner: driver owner
+ * @name: driver name
+ * @max_slaves: maximum number of slave devices
+ * @driver_id: unique id
+ * @probe: function called on probe
+ * @remove: function called on remove
+ * @set_online: function called when device is set online
+ * @set_offline: function called when device is set offline
+ * @driver: embedded driver structure
+ */
 struct ccwgroup_driver {
 	struct module *owner;
 	char *name;
@@ -28,7 +50,7 @@
 	int (*set_online) (struct ccwgroup_device *);
 	int (*set_offline) (struct ccwgroup_device *);
 
-	struct device_driver driver;		/* this driver */
+	struct device_driver driver;
 };
 
 extern int  ccwgroup_driver_register   (struct ccwgroup_driver *cdriver);
diff --git a/include/asm-s390/cio.h b/include/asm-s390/cio.h
index 1982fb3..2f08c16 100644
--- a/include/asm-s390/cio.h
+++ b/include/asm-s390/cio.h
@@ -15,30 +15,50 @@
 #define LPM_ANYPATH 0xff
 #define __MAX_CSSID 0
 
-/*
- * subchannel status word
+/**
+ * struct scsw - subchannel status word
+ * @key: subchannel key
+ * @sctl: suspend control
+ * @eswf: esw format
+ * @cc: deferred condition code
+ * @fmt: format
+ * @pfch: prefetch
+ * @isic: initial-status interruption control
+ * @alcc: adress-limit checking control
+ * @ssi: supress-suspended interruption
+ * @zcc: zero condition code
+ * @ectl: extended control
+ * @pno: path not operational
+ * @res: reserved
+ * @fctl: function control
+ * @actl: activity control
+ * @stctl: status control
+ * @cpa: channel program address
+ * @dstat: device status
+ * @cstat: subchannel status
+ * @count: residual count
  */
 struct scsw {
-	__u32 key  : 4;		/* subchannel key */
-	__u32 sctl : 1; 	/* suspend control */
-	__u32 eswf : 1; 	/* ESW format */
-	__u32 cc   : 2; 	/* deferred condition code */
-	__u32 fmt  : 1; 	/* format */
-	__u32 pfch : 1; 	/* prefetch */
-	__u32 isic : 1; 	/* initial-status interruption control */
-	__u32 alcc : 1; 	/* address-limit checking control */
-	__u32 ssi  : 1; 	/* supress-suspended interruption */
-	__u32 zcc  : 1; 	/* zero condition code */
-	__u32 ectl : 1; 	/* extended control */
-	__u32 pno  : 1;	    	/* path not operational */
-	__u32 res  : 1;	    	/* reserved */
-	__u32 fctl : 3;	    	/* function control */
-	__u32 actl : 7;	    	/* activity control */
-	__u32 stctl : 5;    	/* status control */
-	__u32 cpa;	    	/* channel program address */
-	__u32 dstat : 8;    	/* device status */
-	__u32 cstat : 8;    	/* subchannel status */
-	__u32 count : 16;   	/* residual count */
+	__u32 key  : 4;
+	__u32 sctl : 1;
+	__u32 eswf : 1;
+	__u32 cc   : 2;
+	__u32 fmt  : 1;
+	__u32 pfch : 1;
+	__u32 isic : 1;
+	__u32 alcc : 1;
+	__u32 ssi  : 1;
+	__u32 zcc  : 1;
+	__u32 ectl : 1;
+	__u32 pno  : 1;
+	__u32 res  : 1;
+	__u32 fctl : 3;
+	__u32 actl : 7;
+	__u32 stctl : 5;
+	__u32 cpa;
+	__u32 dstat : 8;
+	__u32 cstat : 8;
+	__u32 count : 16;
 } __attribute__ ((packed));
 
 #define SCSW_FCTL_CLEAR_FUNC	 0x1
@@ -110,11 +130,22 @@
 #define SNS2_ENV_DATA_PRESENT	0x10
 #define SNS2_INPRECISE_END	0x04
 
+/**
+ * struct ccw1 - channel command word
+ * @cmd_code: command code
+ * @flags: flags, like IDA adressing, etc.
+ * @count: byte count
+ * @cda: data address
+ *
+ * The ccw is the basic structure to build channel programs that perform
+ * operations with the device or the control unit. Only Format-1 channel
+ * command words are supported.
+ */
 struct ccw1 {
-	__u8  cmd_code;		/* command code */
-	__u8  flags;   		/* flags, like IDA addressing, etc. */
-	__u16 count;   		/* byte count */
-	__u32 cda;     		/* data address */
+	__u8  cmd_code;
+	__u8  flags;
+	__u16 count;
+	__u32 cda;
 } __attribute__ ((packed,aligned(8)));
 
 #define CCW_FLAG_DC		0x80
@@ -140,102 +171,162 @@
 
 #define SENSE_MAX_COUNT		0x20
 
+/**
+ * struct erw - extended report word
+ * @res0: reserved
+ * @auth: authorization check
+ * @pvrf: path-verification-required flag
+ * @cpt: channel-path timeout
+ * @fsavf: failing storage address validity flag
+ * @cons: concurrent sense
+ * @scavf: secondary ccw address validity flag
+ * @fsaf: failing storage address format
+ * @scnt: sense count, if @cons == %1
+ * @res16: reserved
+ */
 struct erw {
-	__u32 res0  : 3;  	/* reserved */
-	__u32 auth  : 1;	/* Authorization check */
-	__u32 pvrf  : 1;  	/* path-verification-required flag */
-	__u32 cpt   : 1;  	/* channel-path timeout */
-	__u32 fsavf : 1;  	/* Failing storage address validity flag */
-	__u32 cons  : 1;  	/* concurrent-sense */
-	__u32 scavf : 1;	/* Secondary ccw address validity flag */
-	__u32 fsaf  : 1;	/* Failing storage address format */
-	__u32 scnt  : 6;  	/* sense count if cons == 1 */
-	__u32 res16 : 16; 	/* reserved */
+	__u32 res0  : 3;
+	__u32 auth  : 1;
+	__u32 pvrf  : 1;
+	__u32 cpt   : 1;
+	__u32 fsavf : 1;
+	__u32 cons  : 1;
+	__u32 scavf : 1;
+	__u32 fsaf  : 1;
+	__u32 scnt  : 6;
+	__u32 res16 : 16;
 } __attribute__ ((packed));
 
-/*
- * subchannel logout area
+/**
+ * struct sublog - subchannel logout area
+ * @res0: reserved
+ * @esf: extended status flags
+ * @lpum: last path used mask
+ * @arep: ancillary report
+ * @fvf: field-validity flags
+ * @sacc: storage access code
+ * @termc: termination code
+ * @devsc: device-status check
+ * @serr: secondary error
+ * @ioerr: i/o-error alert
+ * @seqc: sequence code
  */
 struct sublog {
-	__u32 res0  : 1;  	/* reserved */
-	__u32 esf   : 7;  	/* extended status flags */
-	__u32 lpum  : 8;  	/* last path used mask */
-	__u32 arep  : 1;  	/* ancillary report */
-	__u32 fvf   : 5;  	/* field-validity flags */
-	__u32 sacc  : 2;  	/* storage access code */
-	__u32 termc : 2;  	/* termination code */
-	__u32 devsc : 1;  	/* device-status check */
-	__u32 serr  : 1;  	/* secondary error */
-	__u32 ioerr : 1;  	/* i/o-error alert */
-	__u32 seqc  : 3;  	/* sequence code */
+	__u32 res0  : 1;
+	__u32 esf   : 7;
+	__u32 lpum  : 8;
+	__u32 arep  : 1;
+	__u32 fvf   : 5;
+	__u32 sacc  : 2;
+	__u32 termc : 2;
+	__u32 devsc : 1;
+	__u32 serr  : 1;
+	__u32 ioerr : 1;
+	__u32 seqc  : 3;
 } __attribute__ ((packed));
 
-/*
- * Format 0 Extended Status Word (ESW)
+/**
+ * struct esw0 - Format 0 Extended Status Word (ESW)
+ * @sublog: subchannel logout
+ * @erw: extended report word
+ * @faddr: failing storage address
+ * @saddr: secondary ccw address
  */
 struct esw0 {
-	struct sublog sublog;	/* subchannel logout */
-	struct erw erw;	    	/* extended report word */
-	__u32  faddr[2];    	/* failing storage address */
-	__u32  saddr;  		/* secondary ccw address */
+	struct sublog sublog;
+	struct erw erw;
+	__u32  faddr[2];
+	__u32  saddr;
 } __attribute__ ((packed));
 
-/*
- * Format 1 Extended Status Word (ESW)
+/**
+ * struct esw1 - Format 1 Extended Status Word (ESW)
+ * @zero0: reserved zeros
+ * @lpum: last path used mask
+ * @zero16: reserved zeros
+ * @erw: extended report word
+ * @zeros: three fullwords of zeros
  */
 struct esw1 {
-	__u8  zero0;		/* reserved zeros */
-	__u8  lpum;		/* last path used mask */
-	__u16 zero16;		/* reserved zeros */
-	struct erw erw;		/* extended report word */
-	__u32 zeros[3]; 	/* 2 fullwords of zeros */
+	__u8  zero0;
+	__u8  lpum;
+	__u16 zero16;
+	struct erw erw;
+	__u32 zeros[3];
 } __attribute__ ((packed));
 
-/*
- * Format 2 Extended Status Word (ESW)
+/**
+ * struct esw2 - Format 2 Extended Status Word (ESW)
+ * @zero0: reserved zeros
+ * @lpum: last path used mask
+ * @dcti: device-connect-time interval
+ * @erw: extended report word
+ * @zeros: three fullwords of zeros
  */
 struct esw2 {
-	__u8  zero0;		/* reserved zeros */
-	__u8  lpum;		/* last path used mask */
-	__u16 dcti;		/* device-connect-time interval */
-	struct erw erw;		/* extended report word */
-	__u32 zeros[3]; 	/* 2 fullwords of zeros */
+	__u8  zero0;
+	__u8  lpum;
+	__u16 dcti;
+	struct erw erw;
+	__u32 zeros[3];
 } __attribute__ ((packed));
 
-/*
- * Format 3 Extended Status Word (ESW)
+/**
+ * struct esw3 - Format 3 Extended Status Word (ESW)
+ * @zero0: reserved zeros
+ * @lpum: last path used mask
+ * @res: reserved
+ * @erw: extended report word
+ * @zeros: three fullwords of zeros
  */
 struct esw3 {
-	__u8  zero0;		/* reserved zeros */
-	__u8  lpum;		/* last path used mask */
-	__u16 res;		/* reserved */
-	struct erw erw;		/* extended report word */
-	__u32 zeros[3]; 	/* 2 fullwords of zeros */
+	__u8  zero0;
+	__u8  lpum;
+	__u16 res;
+	struct erw erw;
+	__u32 zeros[3];
 } __attribute__ ((packed));
 
-/*
- * interruption response block
+/**
+ * struct irb - interruption response block
+ * @scsw: subchannel status word
+ * @esw: extened status word, 4 formats
+ * @ecw: extended control word
+ *
+ * The irb that is handed to the device driver when an interrupt occurs. For
+ * solicited interrupts, the common I/O layer already performs checks whether
+ * a field is valid; a field not being valid is always passed as %0.
+ * If a unit check occured, @ecw may contain sense data; this is retrieved
+ * by the common I/O layer itself if the device doesn't support concurrent
+ * sense (so that the device driver never needs to perform basic sene itself).
+ * For unsolicited interrupts, the irb is passed as-is (expect for sense data,
+ * if applicable).
  */
 struct irb {
-	struct scsw scsw;	/* subchannel status word */
-	union {			/* extended status word, 4 formats */
+	struct scsw scsw;
+	union {
 		struct esw0 esw0;
 		struct esw1 esw1;
 		struct esw2 esw2;
 		struct esw3 esw3;
 	} esw;
-	__u8   ecw[32];		/* extended control word */
+	__u8   ecw[32];
 } __attribute__ ((packed,aligned(4)));
 
-/*
- * command information word  (CIW) layout
+/**
+ * struct ciw - command information word  (CIW) layout
+ * @et: entry type
+ * @reserved: reserved bits
+ * @ct: command type
+ * @cmd: command code
+ * @count: command count
  */
 struct ciw {
-	__u32 et       :  2; 	/* entry type */
-	__u32 reserved :  2; 	/* reserved */
-	__u32 ct       :  4; 	/* command type */
-	__u32 cmd      :  8; 	/* command */
-	__u32 count    : 16; 	/* coun */
+	__u32 et       :  2;
+	__u32 reserved :  2;
+	__u32 ct       :  4;
+	__u32 cmd      :  8;
+	__u32 count    : 16;
 } __attribute__ ((packed));
 
 #define CIW_TYPE_RCD	0x0    	/* read configuration data */
@@ -258,11 +349,32 @@
 /* Sick revalidation of device. */
 #define CIO_REVALIDATE 0x0008
 
+/**
+ * struct ccw_dev_id - unique identifier for ccw devices
+ * @ssid: subchannel set id
+ * @devno: device number
+ *
+ * This structure is not directly based on any hardware structure. The
+ * hardware identifies a device by its device number and its subchannel,
+ * which is in turn identified by its id. In order to get a unique identifier
+ * for ccw devices across subchannel sets, @struct ccw_dev_id has been
+ * introduced.
+ */
 struct ccw_dev_id {
 	u8 ssid;
 	u16 devno;
 };
 
+/**
+ * ccw_device_id_is_equal() - compare two ccw_dev_ids
+ * @dev_id1: a ccw_dev_id
+ * @dev_id2: another ccw_dev_id
+ * Returns:
+ *  %1 if the two structures are equal field-by-field,
+ *  %0 if not.
+ * Context:
+ *  any
+ */
 static inline int ccw_dev_id_is_equal(struct ccw_dev_id *dev_id1,
 				      struct ccw_dev_id *dev_id2)
 {
diff --git a/include/asm-s390/cmb.h b/include/asm-s390/cmb.h
index 021e7c3..5019685 100644
--- a/include/asm-s390/cmb.h
+++ b/include/asm-s390/cmb.h
@@ -1,29 +1,29 @@
 #ifndef S390_CMB_H
 #define S390_CMB_H
 /**
- * struct cmbdata -- channel measurement block data for user space
+ * struct cmbdata - channel measurement block data for user space
+ * @size: size of the stored data
+ * @elapsed_time: time since last sampling
+ * @ssch_rsch_count: number of ssch and rsch
+ * @sample_count: number of samples
+ * @device_connect_time: time of device connect
+ * @function_pending_time: time of function pending
+ * @device_disconnect_time: time of device disconnect
+ * @control_unit_queuing_time: time of control unit queuing
+ * @device_active_only_time: time of device active only
+ * @device_busy_time: time of device busy (ext. format)
+ * @initial_command_response_time: initial command response time (ext. format)
  *
- * @size:	size of the stored data
- * @ssch_rsch_count: XXX
- * @sample_count:
- * @device_connect_time:
- * @function_pending_time:
- * @device_disconnect_time:
- * @control_unit_queuing_time:
- * @device_active_only_time:
- * @device_busy_time:
- * @initial_command_response_time:
- *
- * all values are stored as 64 bit for simplicity, especially
+ * All values are stored as 64 bit for simplicity, especially
  * in 32 bit emulation mode. All time values are normalized to
  * nanoseconds.
  * Currently, two formats are known, which differ by the size of
  * this structure, i.e. the last two members are only set when
  * the extended channel measurement facility (first shipped in
  * z990 machines) is activated.
- * Potentially, more fields could be added, which results in a
+ * Potentially, more fields could be added, which would result in a
  * new ioctl number.
- **/
+ */
 struct cmbdata {
 	__u64 size;
 	__u64 elapsed_time;
@@ -41,53 +41,18 @@
 };
 
 /* enable channel measurement */
-#define BIODASDCMFENABLE	_IO(DASD_IOCTL_LETTER,32)
+#define BIODASDCMFENABLE	_IO(DASD_IOCTL_LETTER, 32)
 /* enable channel measurement */
-#define BIODASDCMFDISABLE	_IO(DASD_IOCTL_LETTER,33)
+#define BIODASDCMFDISABLE	_IO(DASD_IOCTL_LETTER, 33)
 /* read channel measurement data */
-#define BIODASDREADALLCMB	_IOWR(DASD_IOCTL_LETTER,33,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
- *  returns 0 for success or a negative error value.
- *
- *  Context:
- *    non-atomic
- **/
 extern int enable_cmf(struct ccw_device *cdev);
-
-/**
- * disable_cmf() - switch off the channel measurement for a specific device
- *  @cdev:	The ccw device to be disabled
- *  returns 0 for success or a negative error value.
- *
- *  Context:
- *    non-atomic
- **/
 extern int disable_cmf(struct ccw_device *cdev);
-
-/**
- * cmf_read() - read one value from the current channel measurement block
- * @cmf:	the channel to be read
- * @index:	the name of the value that is read
- *
- *  Context:
- *    any
- **/
-
 extern u64 cmf_read(struct ccw_device *cdev, int index);
-/**
- * cmf_readall() - read one value from the current channel measurement block
- * @cmf:	the channel to be read
- * @data:	a pointer to a data block that will be filled
- *
- *  Context:
- *    any
- **/
-extern int cmf_readall(struct ccw_device *cdev, struct cmbdata*data);
+extern int cmf_readall(struct ccw_device *cdev, struct cmbdata *data);
 
 #endif /* __KERNEL__ */
 #endif /* S390_CMB_H */
diff --git a/include/asm-s390/page.h b/include/asm-s390/page.h
index f326451..ceec382 100644
--- a/include/asm-s390/page.h
+++ b/include/asm-s390/page.h
@@ -9,11 +9,12 @@
 #ifndef _S390_PAGE_H
 #define _S390_PAGE_H
 
+#include <linux/const.h>
 #include <asm/types.h>
 
 /* PAGE_SHIFT determines the page size */
 #define PAGE_SHIFT      12
-#define PAGE_SIZE       (1UL << PAGE_SHIFT)
+#define PAGE_SIZE	(_AC(1,UL) << PAGE_SHIFT)
 #define PAGE_MASK       (~(PAGE_SIZE-1))
 #define PAGE_DEFAULT_ACC	0
 #define PAGE_DEFAULT_KEY	(PAGE_DEFAULT_ACC << 4)
diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h
index 3208dc6..39bb519 100644
--- a/include/asm-s390/pgtable.h
+++ b/include/asm-s390/pgtable.h
@@ -107,11 +107,18 @@
  * 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. ;)
+ * vmalloc area starts at 4GB to prevent syscall table entry exchanging
+ * from modules.
  */
 extern unsigned long vmalloc_end;
-#define VMALLOC_OFFSET  (8*1024*1024)
-#define VMALLOC_START   (((unsigned long) high_memory + VMALLOC_OFFSET) \
-			 & ~(VMALLOC_OFFSET-1))
+
+#ifdef CONFIG_64BIT
+#define VMALLOC_ADDR	(max(0x100000000UL, (unsigned long) high_memory))
+#else
+#define VMALLOC_ADDR	((unsigned long) high_memory)
+#endif
+#define VMALLOC_OFFSET	(8*1024*1024)
+#define VMALLOC_START	((VMALLOC_ADDR + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
 #define VMALLOC_END	vmalloc_end
 
 /*
diff --git a/include/asm-s390/s390_ext.h b/include/asm-s390/s390_ext.h
index 1e72362..2afc060 100644
--- a/include/asm-s390/s390_ext.h
+++ b/include/asm-s390/s390_ext.h
@@ -5,7 +5,7 @@
  *  include/asm-s390/s390_ext.h
  *
  *  S390 version
- *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Copyright IBM Corp. 1999,2007
  *    Author(s): Holger Smolinski (Holger.Smolinski@de.ibm.com),
  *               Martin Schwidefsky (schwidefsky@de.ibm.com)
  */
@@ -14,15 +14,11 @@
 
 typedef void (*ext_int_handler_t)(__u16 code);
 
-/*
- * Warning: if you change ext_int_info_t you have to change the
- * external interrupt handler in entry.S too.
- */ 
 typedef struct ext_int_info_t {
 	struct ext_int_info_t *next;
 	ext_int_handler_t handler;
 	__u16 code;
-} __attribute__ ((packed)) ext_int_info_t;
+} ext_int_info_t;
 
 extern ext_int_info_t *ext_int_hash[];
 
diff --git a/include/asm-s390/system.h b/include/asm-s390/system.h
index 64a3cd0..d866d33 100644
--- a/include/asm-s390/system.h
+++ b/include/asm-s390/system.h
@@ -130,6 +130,8 @@
 	__ret;								  \
 })
 
+extern void __xchg_called_with_bad_pointer(void);
+
 static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
 {
 	unsigned long addr, old;
@@ -150,8 +152,7 @@
 			: "=&d" (old), "=m" (*(int *) addr)
 			: "d" (x << shift), "d" (~(255 << shift)), "a" (addr),
 			  "m" (*(int *) addr) : "memory", "cc", "0");
-		x = old >> shift;
-		break;
+		return old >> shift;
 	case 2:
 		addr = (unsigned long) ptr;
 		shift = (2 ^ (addr & 2)) << 3;
@@ -166,8 +167,7 @@
 			: "=&d" (old), "=m" (*(int *) addr)
 			: "d" (x << shift), "d" (~(65535 << shift)), "a" (addr),
 			  "m" (*(int *) addr) : "memory", "cc", "0");
-		x = old >> shift;
-		break;
+		return old >> shift;
 	case 4:
 		asm volatile(
 			"	l	%0,0(%3)\n"
@@ -176,8 +176,7 @@
 			: "=&d" (old), "=m" (*(int *) ptr)
 			: "d" (x), "a" (ptr), "m" (*(int *) ptr)
 			: "memory", "cc");
-		x = old;
-		break;
+		return old;
 #ifdef __s390x__
 	case 8:
 		asm volatile(
@@ -187,11 +186,11 @@
 			: "=&d" (old), "=m" (*(long *) ptr)
 			: "d" (x), "a" (ptr), "m" (*(long *) ptr)
 			: "memory", "cc");
-		x = old;
-		break;
+		return old;
 #endif /* __s390x__ */
-        }
-        return x;
+	}
+	__xchg_called_with_bad_pointer();
+	return x;
 }
 
 /*
@@ -206,6 +205,8 @@
 	((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
 					(unsigned long)(n),sizeof(*(ptr))))
 
+extern void __cmpxchg_called_with_bad_pointer(void);
+
 static inline unsigned long
 __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
 {
@@ -270,7 +271,8 @@
 		return prev;
 #endif /* __s390x__ */
         }
-        return old;
+	__cmpxchg_called_with_bad_pointer();
+	return old;
 }
 
 /*
diff --git a/include/asm-s390/zcrypt.h b/include/asm-s390/zcrypt.h
index b90e558..a5dada6 100644
--- a/include/asm-s390/zcrypt.h
+++ b/include/asm-s390/zcrypt.h
@@ -91,7 +91,7 @@
  *	    VUD block
  *	    key block
  */
-struct ica_CPRBX {
+struct CPRBX {
 	unsigned short	cprb_len;	/* CPRB length	      220	 */
 	unsigned char	cprb_ver_id;	/* CPRB version id.   0x02	 */
 	unsigned char	pad_000[3];	/* Alignment pad bytes		 */
@@ -130,7 +130,7 @@
 	unsigned char	cntrl_domain[4];/* Control domain		 */
 	unsigned char	S390enf_mask[4];/* S/390 enforcement mask	 */
 	unsigned char	pad_004[36];	/* reserved			 */
-};
+} __attribute__((packed));
 
 /**
  * xcRB
diff --git a/include/asm-x86/8253pit.h b/include/asm-x86/8253pit.h
deleted file mode 100644
index d3c2b38..0000000
--- a/include/asm-x86/8253pit.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#ifdef CONFIG_X86_32
-# include "8253pit_32.h"
-#else
-# include "8253pit_64.h"
-#endif
diff --git a/include/asm-x86/8253pit_32.h b/include/asm-x86/8253pit_32.h
deleted file mode 100644
index 96c7c35..0000000
--- a/include/asm-x86/8253pit_32.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * 8253/8254 Programmable Interval Timer
- */
-
-#ifndef _8253PIT_H
-#define _8253PIT_H
-
-#include <asm/timex.h>
-
-#define PIT_TICK_RATE 	CLOCK_TICK_RATE
-
-#endif
diff --git a/include/asm-x86/8253pit_64.h b/include/asm-x86/8253pit_64.h
deleted file mode 100644
index 285f784..0000000
--- a/include/asm-x86/8253pit_64.h
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * 8253/8254 Programmable Interval Timer
- */
-
-#ifndef _8253PIT_H
-#define _8253PIT_H
-
-#define PIT_TICK_RATE 	1193182UL
-
-#endif
diff --git a/include/asm-x86/apic_64.h b/include/asm-x86/apic_64.h
index 85125ef..3c8f21e 100644
--- a/include/asm-x86/apic_64.h
+++ b/include/asm-x86/apic_64.h
@@ -19,7 +19,7 @@
 extern int apic_verbosity;
 extern int apic_runs_main_timer;
 extern int ioapic_force;
-extern int apic_mapped;
+extern int disable_apic_timer;
 
 /*
  * Define the default level of output to be very little
@@ -79,8 +79,6 @@
 extern void setup_boot_APIC_clock (void);
 extern void setup_secondary_APIC_clock (void);
 extern int APIC_init_uniprocessor (void);
-extern void disable_APIC_timer(void);
-extern void enable_APIC_timer(void);
 extern void setup_apic_routing(void);
 
 extern void setup_APIC_extended_lvt(unsigned char lvt_off, unsigned char vector,
@@ -95,10 +93,6 @@
 #define K8_APIC_EXT_INT_MSG_EXT 0x7
 #define K8_APIC_EXT_LVT_ENTRY_THRESHOLD    0
 
-void smp_send_timer_broadcast_ipi(void);
-void switch_APIC_timer_to_ipi(void *cpumask);
-void switch_ipi_to_APIC_timer(void *cpumask);
-
 #define ARCH_APICTIMER_STOPS_ON_C3	1
 
 extern unsigned boot_cpu_id;
diff --git a/include/asm-x86/geode.h b/include/asm-x86/geode.h
index 6da4bbb..d948988 100644
--- a/include/asm-x86/geode.h
+++ b/include/asm-x86/geode.h
@@ -156,4 +156,54 @@
 	return (is_geode_gx() || is_geode_lx());
 }
 
+/* MFGPTs */
+
+#define MFGPT_MAX_TIMERS	8
+#define MFGPT_TIMER_ANY		-1
+
+#define MFGPT_DOMAIN_WORKING	1
+#define MFGPT_DOMAIN_STANDBY	2
+#define MFGPT_DOMAIN_ANY	(MFGPT_DOMAIN_WORKING | MFGPT_DOMAIN_STANDBY)
+
+#define MFGPT_CMP1		0
+#define MFGPT_CMP2		1
+
+#define MFGPT_EVENT_IRQ		0
+#define MFGPT_EVENT_NMI		1
+#define MFGPT_EVENT_RESET	3
+
+#define MFGPT_REG_CMP1		0
+#define MFGPT_REG_CMP2		2
+#define MFGPT_REG_COUNTER	4
+#define MFGPT_REG_SETUP		6
+
+#define MFGPT_SETUP_CNTEN	(1 << 15)
+#define MFGPT_SETUP_CMP2	(1 << 14)
+#define MFGPT_SETUP_CMP1	(1 << 13)
+#define MFGPT_SETUP_SETUP	(1 << 12)
+#define MFGPT_SETUP_STOPEN	(1 << 11)
+#define MFGPT_SETUP_EXTEN	(1 << 10)
+#define MFGPT_SETUP_REVEN	(1 << 5)
+#define MFGPT_SETUP_CLKSEL	(1 << 4)
+
+static inline void geode_mfgpt_write(int timer, u16 reg, u16 value)
+{
+	u32 base = geode_get_dev_base(GEODE_DEV_MFGPT);
+	outw(value, base + reg + (timer * 8));
+}
+
+static inline u16 geode_mfgpt_read(int timer, u16 reg)
+{
+	u32 base = geode_get_dev_base(GEODE_DEV_MFGPT);
+	return inw(base + reg + (timer * 8));
+}
+
+extern int __init geode_mfgpt_detect(void);
+extern int geode_mfgpt_toggle_event(int timer, int cmp, int event, int enable);
+extern int geode_mfgpt_set_irq(int timer, int cmp, int irq, int enable);
+extern int geode_mfgpt_alloc_timer(int timer, int domain, struct module *owner);
+
+#define geode_mfgpt_setup_irq(t, c, i) geode_mfgpt_set_irq((t), (c), (i), 1)
+#define geode_mfgpt_release_irq(t, c, i) geode_mfgpt_set_irq((t), (c), (i), 0)
+
 #endif
diff --git a/include/asm-x86/hardirq_32.h b/include/asm-x86/hardirq_32.h
index 0e358dc..3464958 100644
--- a/include/asm-x86/hardirq_32.h
+++ b/include/asm-x86/hardirq_32.h
@@ -9,6 +9,7 @@
 	unsigned long idle_timestamp;
 	unsigned int __nmi_count;	/* arch dependent */
 	unsigned int apic_timer_irqs;	/* arch dependent */
+	unsigned int irq0_irqs;
 } ____cacheline_aligned irq_cpustat_t;
 
 DECLARE_PER_CPU(irq_cpustat_t, irq_stat);
diff --git a/include/asm-x86/hpet.h b/include/asm-x86/hpet.h
index 9eff486..d4ab6db 100644
--- a/include/asm-x86/hpet.h
+++ b/include/asm-x86/hpet.h
@@ -1,5 +1,93 @@
-#ifdef CONFIG_X86_32
-# include "hpet_32.h"
+#ifndef ASM_X86_HPET_H
+#define ASM_X86_HPET_H
+
+#ifdef CONFIG_HPET_TIMER
+
+/*
+ * Documentation on HPET can be found at:
+ *      http://www.intel.com/ial/home/sp/pcmmspec.htm
+ *      ftp://download.intel.com/ial/home/sp/mmts098.pdf
+ */
+
+#define HPET_MMAP_SIZE		1024
+
+#define HPET_ID			0x000
+#define HPET_PERIOD		0x004
+#define HPET_CFG		0x010
+#define HPET_STATUS		0x020
+#define HPET_COUNTER		0x0f0
+#define HPET_T0_CFG		0x100
+#define HPET_T0_CMP		0x108
+#define HPET_T0_ROUTE		0x110
+#define HPET_T1_CFG		0x120
+#define HPET_T1_CMP		0x128
+#define HPET_T1_ROUTE		0x130
+#define HPET_T2_CFG		0x140
+#define HPET_T2_CMP		0x148
+#define HPET_T2_ROUTE		0x150
+
+#define HPET_ID_REV		0x000000ff
+#define HPET_ID_NUMBER		0x00001f00
+#define HPET_ID_64BIT		0x00002000
+#define HPET_ID_LEGSUP		0x00008000
+#define HPET_ID_VENDOR		0xffff0000
+#define	HPET_ID_NUMBER_SHIFT	8
+#define HPET_ID_VENDOR_SHIFT	16
+
+#define HPET_ID_VENDOR_8086	0x8086
+
+#define HPET_CFG_ENABLE		0x001
+#define HPET_CFG_LEGACY		0x002
+#define	HPET_LEGACY_8254	2
+#define	HPET_LEGACY_RTC		8
+
+#define HPET_TN_LEVEL		0x0002
+#define HPET_TN_ENABLE		0x0004
+#define HPET_TN_PERIODIC	0x0008
+#define HPET_TN_PERIODIC_CAP	0x0010
+#define HPET_TN_64BIT_CAP	0x0020
+#define HPET_TN_SETVAL		0x0040
+#define HPET_TN_32BIT		0x0100
+#define HPET_TN_ROUTE		0x3e00
+#define HPET_TN_FSB		0x4000
+#define HPET_TN_FSB_CAP		0x8000
+#define HPET_TN_ROUTE_SHIFT	9
+
+/* Max HPET Period is 10^8 femto sec as in HPET spec */
+#define HPET_MAX_PERIOD		100000000UL
+/*
+ * Min HPET period is 10^5 femto sec just for safety. If it is less than this,
+ * then 32 bit HPET counter wrapsaround in less than 0.5 sec.
+ */
+#define HPET_MIN_PERIOD		100000UL
+
+/* hpet memory map physical address */
+extern unsigned long hpet_address;
+extern unsigned long force_hpet_address;
+extern int is_hpet_enabled(void);
+extern int hpet_enable(void);
+extern unsigned long hpet_readl(unsigned long a);
+extern void force_hpet_resume(void);
+
+#ifdef CONFIG_HPET_EMULATE_RTC
+
+#include <linux/interrupt.h>
+
+extern int hpet_mask_rtc_irq_bit(unsigned long bit_mask);
+extern int hpet_set_rtc_irq_bit(unsigned long bit_mask);
+extern int hpet_set_alarm_time(unsigned char hrs, unsigned char min,
+			       unsigned char sec);
+extern int hpet_set_periodic_freq(unsigned long freq);
+extern int hpet_rtc_dropped_irq(void);
+extern int hpet_rtc_timer_init(void);
+extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id);
+
+#endif /* CONFIG_HPET_EMULATE_RTC */
+
 #else
-# include "hpet_64.h"
-#endif
+
+static inline int hpet_enable(void) { return 0; }
+static inline unsigned long hpet_readl(unsigned long a) { return 0; }
+
+#endif /* CONFIG_HPET_TIMER */
+#endif /* ASM_X86_HPET_H */
diff --git a/include/asm-x86/hpet_32.h b/include/asm-x86/hpet_32.h
deleted file mode 100644
index c82dc7e..0000000
--- a/include/asm-x86/hpet_32.h
+++ /dev/null
@@ -1,90 +0,0 @@
-
-#ifndef _I386_HPET_H
-#define _I386_HPET_H
-
-#ifdef CONFIG_HPET_TIMER
-
-/*
- * Documentation on HPET can be found at:
- *      http://www.intel.com/ial/home/sp/pcmmspec.htm
- *      ftp://download.intel.com/ial/home/sp/mmts098.pdf
- */
-
-#define HPET_MMAP_SIZE		1024
-
-#define HPET_ID			0x000
-#define HPET_PERIOD		0x004
-#define HPET_CFG		0x010
-#define HPET_STATUS		0x020
-#define HPET_COUNTER		0x0f0
-#define HPET_T0_CFG		0x100
-#define HPET_T0_CMP		0x108
-#define HPET_T0_ROUTE		0x110
-#define HPET_T1_CFG		0x120
-#define HPET_T1_CMP		0x128
-#define HPET_T1_ROUTE		0x130
-#define HPET_T2_CFG		0x140
-#define HPET_T2_CMP		0x148
-#define HPET_T2_ROUTE		0x150
-
-#define HPET_ID_REV		0x000000ff
-#define HPET_ID_NUMBER		0x00001f00
-#define HPET_ID_64BIT		0x00002000
-#define HPET_ID_LEGSUP		0x00008000
-#define HPET_ID_VENDOR		0xffff0000
-#define	HPET_ID_NUMBER_SHIFT	8
-#define HPET_ID_VENDOR_SHIFT	16
-
-#define HPET_ID_VENDOR_8086	0x8086
-
-#define HPET_CFG_ENABLE		0x001
-#define HPET_CFG_LEGACY		0x002
-#define	HPET_LEGACY_8254	2
-#define	HPET_LEGACY_RTC		8
-
-#define HPET_TN_LEVEL		0x0002
-#define HPET_TN_ENABLE		0x0004
-#define HPET_TN_PERIODIC	0x0008
-#define HPET_TN_PERIODIC_CAP	0x0010
-#define HPET_TN_64BIT_CAP	0x0020
-#define HPET_TN_SETVAL		0x0040
-#define HPET_TN_32BIT		0x0100
-#define HPET_TN_ROUTE		0x3e00
-#define HPET_TN_FSB		0x4000
-#define HPET_TN_FSB_CAP		0x8000
-#define HPET_TN_ROUTE_SHIFT	9
-
-/* Max HPET Period is 10^8 femto sec as in HPET spec */
-#define HPET_MAX_PERIOD		100000000UL
-/*
- * Min HPET period is 10^5 femto sec just for safety. If it is less than this,
- * then 32 bit HPET counter wrapsaround in less than 0.5 sec.
- */
-#define HPET_MIN_PERIOD		100000UL
-
-/* hpet memory map physical address */
-extern unsigned long hpet_address;
-extern int is_hpet_enabled(void);
-extern int hpet_enable(void);
-
-#ifdef CONFIG_HPET_EMULATE_RTC
-
-#include <linux/interrupt.h>
-
-extern int hpet_mask_rtc_irq_bit(unsigned long bit_mask);
-extern int hpet_set_rtc_irq_bit(unsigned long bit_mask);
-extern int hpet_set_alarm_time(unsigned char hrs, unsigned char min,
-			       unsigned char sec);
-extern int hpet_set_periodic_freq(unsigned long freq);
-extern int hpet_rtc_dropped_irq(void);
-extern int hpet_rtc_timer_init(void);
-extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id);
-
-#endif /* CONFIG_HPET_EMULATE_RTC */
-
-#else
-
-static inline int hpet_enable(void) { return 0; }
-
-#endif /* CONFIG_HPET_TIMER */
-#endif /* _I386_HPET_H */
diff --git a/include/asm-x86/hpet_64.h b/include/asm-x86/hpet_64.h
deleted file mode 100644
index fd4deca..0000000
--- a/include/asm-x86/hpet_64.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef _ASM_X8664_HPET_H
-#define _ASM_X8664_HPET_H 1
-
-#include <asm/hpet_32.h>
-
-#define HPET_TICK_RATE (HZ * 100000UL)
-
-extern int hpet_rtc_timer_init(void);
-extern int hpet_arch_init(void);
-extern int hpet_timer_stop_set_go(unsigned long tick);
-extern int hpet_reenable(void);
-extern unsigned int hpet_calibrate_tsc(void);
-
-extern int hpet_use_timer;
-extern unsigned long hpet_period;
-extern unsigned long hpet_tick;
-
-#endif
diff --git a/include/asm-x86/i8253.h b/include/asm-x86/i8253.h
index b2a4f99..747548e 100644
--- a/include/asm-x86/i8253.h
+++ b/include/asm-x86/i8253.h
@@ -1,5 +1,15 @@
-#ifdef CONFIG_X86_32
-# include "i8253_32.h"
-#else
-# include "i8253_64.h"
-#endif
+#ifndef __ASM_I8253_H__
+#define __ASM_I8253_H__
+
+/* i8253A PIT registers */
+#define PIT_MODE		0x43
+#define PIT_CH0			0x40
+#define PIT_CH2			0x42
+
+extern spinlock_t i8253_lock;
+
+extern struct clock_event_device *global_clock_event;
+
+extern void setup_pit_timer(void);
+
+#endif	/* __ASM_I8253_H__ */
diff --git a/include/asm-x86/i8253_32.h b/include/asm-x86/i8253_32.h
deleted file mode 100644
index 7577d05..0000000
--- a/include/asm-x86/i8253_32.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef __ASM_I8253_H__
-#define __ASM_I8253_H__
-
-#include <linux/clockchips.h>
-
-/* i8253A PIT registers */
-#define PIT_MODE		0x43
-#define PIT_CH0			0x40
-#define PIT_CH2			0x42
-
-extern spinlock_t i8253_lock;
-
-extern struct clock_event_device *global_clock_event;
-
-extern void setup_pit_timer(void);
-
-#endif	/* __ASM_I8253_H__ */
diff --git a/include/asm-x86/i8253_64.h b/include/asm-x86/i8253_64.h
deleted file mode 100644
index 015d8df..0000000
--- a/include/asm-x86/i8253_64.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_I8253_H__
-#define __ASM_I8253_H__
-
-extern spinlock_t i8253_lock;
-
-#endif	/* __ASM_I8253_H__ */
diff --git a/include/asm-x86/pda.h b/include/asm-x86/pda.h
index 5642634..fb49f80 100644
--- a/include/asm-x86/pda.h
+++ b/include/asm-x86/pda.h
@@ -29,6 +29,7 @@
 	short isidle;
 	struct mm_struct *active_mm;
 	unsigned apic_timer_irqs;
+	unsigned irq0_irqs;
 } ____cacheline_aligned_in_smp;
 
 extern struct x8664_pda *_cpu_pda[];
diff --git a/include/asm-x86/proto.h b/include/asm-x86/proto.h
index 31f20ad..c44a3a9 100644
--- a/include/asm-x86/proto.h
+++ b/include/asm-x86/proto.h
@@ -51,9 +51,6 @@
 
 extern void load_gs_index(unsigned gs);
 
-extern void stop_timer_interrupt(void);
-extern void main_timer_handler(void);
-
 extern unsigned long end_pfn_map; 
 
 extern void show_trace(struct task_struct *, struct pt_regs *, unsigned long * rsp);
@@ -90,14 +87,10 @@
 
 extern int gsi_irq_sharing(int gsi);
 
-extern void smp_local_timer_interrupt(void);
-
 extern int force_mwait;
 
 long do_arch_prctl(struct task_struct *task, int code, unsigned long addr);
 
-void i8254_timer_resume(void);
-
 #define round_up(x,y) (((x) + (y) - 1) & ~((y)-1))
 #define round_down(x,y) ((x) & ~((y)-1))
 
diff --git a/include/asm-x86/timex.h b/include/asm-x86/timex.h
index d01c18c..39a21ab 100644
--- a/include/asm-x86/timex.h
+++ b/include/asm-x86/timex.h
@@ -1,5 +1,18 @@
-#ifdef CONFIG_X86_32
-# include "timex_32.h"
+/* x86 architecture timex specifications */
+#ifndef _ASM_X86_TIMEX_H
+#define _ASM_X86_TIMEX_H
+
+#include <asm/processor.h>
+#include <asm/tsc.h>
+
+#ifdef CONFIG_X86_ELAN
+#  define PIT_TICK_RATE 1189200 /* AMD Elan has different frequency! */
 #else
-# include "timex_64.h"
+#  define PIT_TICK_RATE 1193182 /* Underlying HZ */
+#endif
+#define CLOCK_TICK_RATE	PIT_TICK_RATE
+
+extern int read_current_timer(unsigned long *timer_value);
+#define ARCH_HAS_READ_CURRENT_TIMER	1
+
 #endif
diff --git a/include/asm-x86/timex_32.h b/include/asm-x86/timex_32.h
deleted file mode 100644
index 3666044..0000000
--- a/include/asm-x86/timex_32.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * linux/include/asm-i386/timex.h
- *
- * i386 architecture timex specifications
- */
-#ifndef _ASMi386_TIMEX_H
-#define _ASMi386_TIMEX_H
-
-#include <asm/processor.h>
-#include <asm/tsc.h>
-
-#ifdef CONFIG_X86_ELAN
-#  define CLOCK_TICK_RATE 1189200 /* AMD Elan has different frequency! */
-#else
-#  define CLOCK_TICK_RATE 1193182 /* Underlying HZ */
-#endif
-
-
-extern int read_current_timer(unsigned long *timer_value);
-#define ARCH_HAS_READ_CURRENT_TIMER	1
-
-#endif
diff --git a/include/asm-x86/timex_64.h b/include/asm-x86/timex_64.h
deleted file mode 100644
index 6ed21f4..0000000
--- a/include/asm-x86/timex_64.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * linux/include/asm-x86_64/timex.h
- *
- * x86-64 architecture timex specifications
- */
-#ifndef _ASMx8664_TIMEX_H
-#define _ASMx8664_TIMEX_H
-
-#include <asm/8253pit.h>
-#include <asm/msr.h>
-#include <asm/vsyscall.h>
-#include <asm/system.h>
-#include <asm/processor.h>
-#include <asm/tsc.h>
-#include <linux/compiler.h>
-
-#define CLOCK_TICK_RATE	PIT_TICK_RATE	/* Underlying HZ */
-
-extern int read_current_timer(unsigned long *timer_value);
-#define ARCH_HAS_READ_CURRENT_TIMER	1
-
-#define USEC_PER_TICK (USEC_PER_SEC / HZ)
-#define NSEC_PER_TICK (NSEC_PER_SEC / HZ)
-#define FSEC_PER_TICK (FSEC_PER_SEC / HZ)
-
-#define NS_SCALE        10 /* 2^10, carefully chosen */
-#define US_SCALE        32 /* 2^32, arbitralrily chosen */
-
-extern void mark_tsc_unstable(char *msg);
-extern void set_cyc2ns_scale(unsigned long khz);
-#endif
diff --git a/include/asm-x86/tsc.h b/include/asm-x86/tsc.h
index a4d8066..6baab30 100644
--- a/include/asm-x86/tsc.h
+++ b/include/asm-x86/tsc.h
@@ -1,13 +1,14 @@
 /*
- * linux/include/asm-i386/tsc.h
- *
- * i386 TSC related functions
+ * x86 TSC related functions
  */
-#ifndef _ASM_i386_TSC_H
-#define _ASM_i386_TSC_H
+#ifndef _ASM_X86_TSC_H
+#define _ASM_X86_TSC_H
 
 #include <asm/processor.h>
 
+#define NS_SCALE	10 /* 2^10, carefully chosen */
+#define US_SCALE	32 /* 2^32, arbitralrily chosen */
+
 /*
  * Standard way to access the cycle counter.
  */
@@ -72,4 +73,8 @@
 extern void check_tsc_sync_source(int cpu);
 extern void check_tsc_sync_target(void);
 
+#ifdef CONFIG_X86_64
+extern void tsc_calibrate(void);
+#endif
+
 #endif
diff --git a/include/asm-x86/vsyscall.h b/include/asm-x86/vsyscall.h
index 3b8ceb4..f01c49f 100644
--- a/include/asm-x86/vsyscall.h
+++ b/include/asm-x86/vsyscall.h
@@ -29,9 +29,6 @@
 #define VGETCPU_RDTSCP	1
 #define VGETCPU_LSL	2
 
-#define hpet_readl(a)           readl((const void __iomem *)fix_to_virt(FIX_HPET_BASE) + a)
-#define hpet_writel(d,a)        writel(d, (void __iomem *)fix_to_virt(FIX_HPET_BASE) + a)
-
 extern int __vgetcpu_mode;
 extern volatile unsigned long __jiffies;
 
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 95be0ac..5ed888b 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -20,20 +20,6 @@
 
 #include <asm/scatterlist.h>
 
-#ifdef CONFIG_LBD
-# include <asm/div64.h>
-# define sector_div(a, b) do_div(a, b)
-#else
-# define sector_div(n, b)( \
-{ \
-	int _res; \
-	_res = (n) % (b); \
-	(n) /= (b); \
-	_res; \
-} \
-)
-#endif
-
 struct scsi_ioctl_command;
 
 struct request_queue;
diff --git a/include/linux/blktrace_api.h b/include/linux/blktrace_api.h
index 2e105a1..7e11d23 100644
--- a/include/linux/blktrace_api.h
+++ b/include/linux/blktrace_api.h
@@ -290,12 +290,7 @@
 #define blk_add_trace_generic(q, rq, rw, what)	do { } while (0)
 #define blk_add_trace_pdu_int(q, what, bio, pdu)	do { } while (0)
 #define blk_add_trace_remap(q, bio, dev, f, t)	do {} while (0)
-static inline int do_blk_trace_setup(struct request_queue *q,
-				     struct block_device *bdev,
-				     struct blk_user_trace_setup *buts)
-{
-	return 0;
-}
+#define do_blk_trace_setup(q, bdev, buts)	(-ENOTTY)
 #endif /* CONFIG_BLK_DEV_IO_TRACE */
 #endif /* __KERNEL__ */
 #endif
diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h
index def5a65..d2ddea9 100644
--- a/include/linux/clockchips.h
+++ b/include/linux/clockchips.h
@@ -8,7 +8,7 @@
 #ifndef _LINUX_CLOCKCHIPS_H
 #define _LINUX_CLOCKCHIPS_H
 
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
+#ifdef CONFIG_GENERIC_CLOCKEVENTS_BUILD
 
 #include <linux/clocksource.h>
 #include <linux/cpumask.h>
@@ -126,11 +126,14 @@
 extern int clockevents_program_event(struct clock_event_device *dev,
 				     ktime_t expires, ktime_t now);
 
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
 extern void clockevents_notify(unsigned long reason, void *arg);
-
 #else
+# define clockevents_notify(reason, arg) do { } while (0)
+#endif
 
-static inline void clockevents_resume_events(void) { }
+#else /* CONFIG_GENERIC_CLOCKEVENTS_BUILD */
+
 #define clockevents_notify(reason, arg) do { } while (0)
 
 #endif
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 3ec6e7f..23932d7 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -32,12 +32,24 @@
  *                     CPUFREQ NOTIFIER INTERFACE                    *
  *********************************************************************/
 
-int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list);
-int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list);
-
 #define CPUFREQ_TRANSITION_NOTIFIER	(0)
 #define CPUFREQ_POLICY_NOTIFIER		(1)
 
+#ifdef CONFIG_CPU_FREQ
+int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list);
+int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list);
+#else		/* CONFIG_CPU_FREQ */
+static inline int cpufreq_register_notifier(struct notifier_block *nb,
+						unsigned int list)
+{
+	return 0;
+}
+static inline int cpufreq_unregister_notifier(struct notifier_block *nb,
+						unsigned int list)
+{
+	return 0;
+}
+#endif		/* CONFIG_CPU_FREQ */
 
 /* if (cpufreq_driver->target) exists, the ->governor decides what frequency
  * within the limits is used. If (cpufreq_driver->setpolicy> exists, these
@@ -155,6 +167,9 @@
 	char	name[CPUFREQ_NAME_LEN];
 	int 	(*governor)	(struct cpufreq_policy *policy,
 				 unsigned int event);
+	unsigned int max_transition_latency; /* HW must be able to switch to
+			next freq faster than this value in nano secs or we
+			will fallback to performance governor */
 	struct list_head	governor_list;
 	struct module		*owner;
 };
@@ -279,12 +294,24 @@
  *********************************************************************/
 
 
-#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE
+/*
+  Performance governor is fallback governor if any other gov failed to
+  auto load due latency restrictions
+*/
+#ifdef CONFIG_CPU_FREQ_GOV_PERFORMANCE
 extern struct cpufreq_governor cpufreq_gov_performance;
-#define CPUFREQ_DEFAULT_GOVERNOR	&cpufreq_gov_performance
+#endif
+#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE
+#define CPUFREQ_DEFAULT_GOVERNOR	(&cpufreq_gov_performance)
 #elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE)
 extern struct cpufreq_governor cpufreq_gov_userspace;
-#define CPUFREQ_DEFAULT_GOVERNOR	&cpufreq_gov_userspace
+#define CPUFREQ_DEFAULT_GOVERNOR	(&cpufreq_gov_userspace)
+#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND)
+extern struct cpufreq_governor cpufreq_gov_ondemand;
+#define CPUFREQ_DEFAULT_GOVERNOR	(&cpufreq_gov_ondemand)
+#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE)
+extern struct cpufreq_governor cpufreq_gov_conservative;
+#define CPUFREQ_DEFAULT_GOVERNOR	(&cpufreq_gov_conservative)
 #endif
 
 
diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h
index 104e51e..f592d6d 100644
--- a/include/linux/debugfs.h
+++ b/include/linux/debugfs.h
@@ -49,6 +49,12 @@
 				  struct dentry *parent, u32 *value);
 struct dentry *debugfs_create_u64(const char *name, mode_t mode,
 				  struct dentry *parent, u64 *value);
+struct dentry *debugfs_create_x8(const char *name, mode_t mode,
+				 struct dentry *parent, u8 *value);
+struct dentry *debugfs_create_x16(const char *name, mode_t mode,
+				  struct dentry *parent, u16 *value);
+struct dentry *debugfs_create_x32(const char *name, mode_t mode,
+				  struct dentry *parent, u32 *value);
 struct dentry *debugfs_create_bool(const char *name, mode_t mode,
 				  struct dentry *parent, u32 *value);
 
@@ -122,6 +128,27 @@
 	return ERR_PTR(-ENODEV);
 }
 
+static inline struct dentry *debugfs_create_x8(const char *name, mode_t mode,
+					       struct dentry *parent,
+					       u8 *value)
+{
+	return ERR_PTR(-ENODEV);
+}
+
+static inline struct dentry *debugfs_create_x16(const char *name, mode_t mode,
+						struct dentry *parent,
+						u16 *value)
+{
+	return ERR_PTR(-ENODEV);
+}
+
+static inline struct dentry *debugfs_create_x32(const char *name, mode_t mode,
+						struct dentry *parent,
+						u32 *value)
+{
+	return ERR_PTR(-ENODEV);
+}
+
 static inline struct dentry *debugfs_create_bool(const char *name, mode_t mode,
 						 struct dentry *parent,
 						 u32 *value)
diff --git a/include/linux/device.h b/include/linux/device.h
index 3a38d1f..2e15822 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -64,12 +64,9 @@
 	struct bus_attribute	* bus_attrs;
 	struct device_attribute	* dev_attrs;
 	struct driver_attribute	* drv_attrs;
-	struct bus_attribute drivers_autoprobe_attr;
-	struct bus_attribute drivers_probe_attr;
 
 	int		(*match)(struct device * dev, struct device_driver * drv);
-	int		(*uevent)(struct device *dev, char **envp,
-				  int num_envp, char *buffer, int buffer_size);
+	int		(*uevent)(struct device *dev, struct kobj_uevent_env *env);
 	int		(*probe)(struct device * dev);
 	int		(*remove)(struct device * dev);
 	void		(*shutdown)(struct device * dev);
@@ -189,10 +186,8 @@
 	struct class_device_attribute	* class_dev_attrs;
 	struct device_attribute		* dev_attrs;
 
-	int	(*uevent)(struct class_device *dev, char **envp,
-			   int num_envp, char *buffer, int buffer_size);
-	int	(*dev_uevent)(struct device *dev, char **envp, int num_envp,
-				char *buffer, int buffer_size);
+	int	(*uevent)(struct class_device *dev, struct kobj_uevent_env *env);
+	int	(*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);
 
 	void	(*release)(struct class_device *dev);
 	void	(*class_release)(struct class *class);
@@ -268,8 +263,7 @@
 	struct attribute_group  ** groups;	/* optional groups */
 
 	void	(*release)(struct class_device *dev);
-	int	(*uevent)(struct class_device *dev, char **envp,
-			   int num_envp, char *buffer, int buffer_size);
+	int	(*uevent)(struct class_device *dev, struct kobj_uevent_env *env);
 	char	class_id[BUS_ID_SIZE];	/* unique to this class */
 };
 
@@ -337,8 +331,7 @@
 struct device_type {
 	const char *name;
 	struct attribute_group **groups;
-	int (*uevent)(struct device *dev, char **envp, int num_envp,
-		      char *buffer, int buffer_size);
+	int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
 	void (*release)(struct device *dev);
 	int (*suspend)(struct device * dev, pm_message_t state);
 	int (*resume)(struct device * dev);
diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h
index a44a6a0..c3c19f9 100644
--- a/include/linux/gfs2_ondisk.h
+++ b/include/linux/gfs2_ondisk.h
@@ -170,6 +170,33 @@
 };
 
 /*
+ * quota linked list: user quotas and group quotas form two separate 
+ * singly linked lists. ll_next stores uids or gids of next quotas in the 
+ * linked list.
+
+Given the uid/gid, how to calculate the quota file offsets for the corresponding
+gfs2_quota structures on disk:
+
+for user quotas, given uid,
+offset = uid * sizeof(struct gfs2_quota);
+
+for group quotas, given gid,
+offset = (gid * sizeof(struct gfs2_quota)) + sizeof(struct gfs2_quota);
+
+
+  uid:0   gid:0       uid:12   gid:12      uid:17   gid:17     uid:5142 gid:5142
++-------+-------+    +-------+-------+    +-------+- - - -+    +- - - -+-------+
+| valid | valid | :: | valid | valid | :: | valid | inval | :: | inval | valid |
++-------+-------+    +-------+-------+    +-------+- - - -+    +- - - -+-------+
+next:12   next:12    next:17 next:5142    next:NULL                    next:NULL
+    |       |            |       |            |<-- user quota list         |
+     \______|___________/ \______|___________/         group quota list -->|
+            |                    |                                         |
+             \__________________/ \_______________________________________/
+
+*/
+
+/*
  * quota structure
  */
 
@@ -177,7 +204,8 @@
 	__be64 qu_limit;
 	__be64 qu_warn;
 	__be64 qu_value;
-	__u8 qu_reserved[64];
+	__be32 qu_ll_next; /* location of next quota in list */
+	__u8 qu_reserved[60];
 };
 
 /*
diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h
index c080f61..d7a5e03 100644
--- a/include/linux/jiffies.h
+++ b/include/linux/jiffies.h
@@ -36,8 +36,6 @@
 /* LATCH is used in the interval timer and ftape setup. */
 #define LATCH  ((CLOCK_TICK_RATE + HZ/2) / HZ)	/* For divider */
 
-#define LATCH_HPET ((HPET_TICK_RATE + HZ/2) / HZ)
-
 /* Suppose we want to devide two numbers NOM and DEN: NOM/DEN, the we can
  * improve accuracy by shifting LSH bits, hence calculating:
  *     (NOM << LSH) / DEN
@@ -53,13 +51,9 @@
 /* HZ is the requested value. ACTHZ is actual HZ ("<< 8" is for accuracy) */
 #define ACTHZ (SH_DIV (CLOCK_TICK_RATE, LATCH, 8))
 
-#define ACTHZ_HPET (SH_DIV (HPET_TICK_RATE, LATCH_HPET, 8))
-
 /* TICK_NSEC is the time between ticks in nsec assuming real ACTHZ */
 #define TICK_NSEC (SH_DIV (1000000UL * 1000, ACTHZ, 8))
 
-#define TICK_NSEC_HPET (SH_DIV(1000000UL * 1000, ACTHZ_HPET, 8))
-
 /* TICK_USEC is the time between ticks in usec assuming fake USER_HZ */
 #define TICK_USEC ((1000000UL + USER_HZ/2) / USER_HZ)
 
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 47160fe..d9725a2 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -42,6 +42,20 @@
 #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
 #define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
 
+#ifdef CONFIG_LBD
+# include <asm/div64.h>
+# define sector_div(a, b) do_div(a, b)
+#else
+# define sector_div(n, b)( \
+{ \
+	int _res; \
+	_res = (n) % (b); \
+	(n) /= (b); \
+	_res; \
+} \
+)
+#endif
+
 /**
  * upper_32_bits - return bits 32-63 of a number
  * @n: the number we're accessing
diff --git a/include/linux/kobject.h b/include/linux/kobject.h
index 949706c..4a0d27f 100644
--- a/include/linux/kobject.h
+++ b/include/linux/kobject.h
@@ -1,8 +1,10 @@
 /*
  * kobject.h - generic kernel object infrastructure.
  *
- * Copyright (c) 2002-2003	Patrick Mochel
- * Copyright (c) 2002-2003	Open Source Development Labs
+ * Copyright (c) 2002-2003 Patrick Mochel
+ * Copyright (c) 2002-2003 Open Source Development Labs
+ * Copyright (c) 2006-2007 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (c) 2006-2007 Novell Inc.
  *
  * This file is released under the GPLv2.
  *
@@ -29,6 +31,8 @@
 
 #define KOBJ_NAME_LEN			20
 #define UEVENT_HELPER_PATH_LEN		256
+#define UEVENT_NUM_ENVP			32	/* number of env pointers */
+#define UEVENT_BUFFER_SIZE		2048	/* buffer for the variables */
 
 /* path to the userspace helper executed on an event */
 extern char uevent_helper[];
@@ -56,19 +60,14 @@
 	KOBJ_MAX
 };
 
-/* The list of strings defining the valid kobject actions as specified above */
-extern const char *kobject_actions[];
-
 struct kobject {
 	const char		* k_name;
-	char			name[KOBJ_NAME_LEN];
 	struct kref		kref;
 	struct list_head	entry;
 	struct kobject		* parent;
 	struct kset		* kset;
 	struct kobj_type	* ktype;
 	struct sysfs_dirent	* sd;
-	wait_queue_head_t	poll;
 };
 
 extern int kobject_set_name(struct kobject *, const char *, ...)
@@ -83,14 +82,9 @@
 extern void kobject_cleanup(struct kobject *);
 
 extern int __must_check kobject_add(struct kobject *);
-extern int __must_check kobject_shadow_add(struct kobject *kobj,
-					   struct sysfs_dirent *shadow_parent);
 extern void kobject_del(struct kobject *);
 
 extern int __must_check kobject_rename(struct kobject *, const char *new_name);
-extern int __must_check kobject_shadow_rename(struct kobject *kobj,
-					      struct sysfs_dirent *new_parent,
-					      const char *new_name);
 extern int __must_check kobject_move(struct kobject *, struct kobject *);
 
 extern int __must_check kobject_register(struct kobject *);
@@ -111,36 +105,44 @@
 	struct attribute	** default_attrs;
 };
 
+struct kobj_uevent_env {
+	char *envp[UEVENT_NUM_ENVP];
+	int envp_idx;
+	char buf[UEVENT_BUFFER_SIZE];
+	int buflen;
+};
+
 struct kset_uevent_ops {
 	int (*filter)(struct kset *kset, struct kobject *kobj);
 	const char *(*name)(struct kset *kset, struct kobject *kobj);
-	int (*uevent)(struct kset *kset, struct kobject *kobj, char **envp,
-			int num_envp, char *buffer, int buffer_size);
+	int (*uevent)(struct kset *kset, struct kobject *kobj,
+		      struct kobj_uevent_env *env);
 };
 
-/*
- *	struct kset - a set of kobjects of a specific type, belonging
- *	to a specific subsystem.
+/**
+ * struct kset - a set of kobjects of a specific type, belonging to a specific subsystem.
  *
- *	All kobjects of a kset should be embedded in an identical 
- *	type. This type may have a descriptor, which the kset points
- *	to. This allows there to exist sets of objects of the same
- *	type in different subsystems.
+ * A kset defines a group of kobjects.  They can be individually
+ * different "types" but overall these kobjects all want to be grouped
+ * together and operated on in the same manner.  ksets are used to
+ * define the attribute callbacks and other common events that happen to
+ * a kobject.
  *
- *	A subsystem does not have to be a list of only one type 
- *	of object; multiple ksets can belong to one subsystem. All 
- *	ksets of a subsystem share the subsystem's lock.
- *
- *	Each kset can support specific event variables; it can
- *	supress the event generation or add subsystem specific
- *	variables carried with the event.
+ * @ktype: the struct kobj_type for this specific kset
+ * @list: the list of all kobjects for this kset
+ * @list_lock: a lock for iterating over the kobjects
+ * @kobj: the embedded kobject for this kset (recursion, isn't it fun...)
+ * @uevent_ops: the set of uevent operations for this kset.  These are
+ * called whenever a kobject has something happen to it so that the kset
+ * can add new environment variables, or filter out the uevents if so
+ * desired.
  */
 struct kset {
-	struct kobj_type	* ktype;
+	struct kobj_type	*ktype;
 	struct list_head	list;
 	spinlock_t		list_lock;
 	struct kobject		kobj;
-	struct kset_uevent_ops	* uevent_ops;
+	struct kset_uevent_ops	*uevent_ops;
 };
 
 
@@ -179,18 +181,18 @@
  * Use this when initializing an embedded kset with no other 
  * fields to initialize.
  */
-#define set_kset_name(str)	.kset = { .kobj = { .name = str } }
+#define set_kset_name(str)	.kset = { .kobj = { .k_name = str } }
 
 
 #define decl_subsys(_name,_type,_uevent_ops) \
 struct kset _name##_subsys = { \
-	.kobj = { .name = __stringify(_name) }, \
+	.kobj = { .k_name = __stringify(_name) }, \
 	.ktype = _type, \
 	.uevent_ops =_uevent_ops, \
 }
 #define decl_subsys_name(_varname,_name,_type,_uevent_ops) \
 struct kset _varname##_subsys = { \
-	.kobj = { .name = __stringify(_name) }, \
+	.kobj = { .k_name = __stringify(_name) }, \
 	.ktype = _type, \
 	.uevent_ops =_uevent_ops, \
 }
@@ -218,49 +220,9 @@
 #define kobj_set_kset_s(obj,subsys) \
 	(obj)->kobj.kset = &(subsys)
 
-/**
- *	kset_set_kset_s(obj,subsys) - set kset for embedded kset.
- *	@obj:		ptr to some object type.
- *	@subsys:	a subsystem object (not a ptr).
- *
- *	Can be used for any object type with an embedded ->kset.
- *	Sets the kset of @obj's  embedded kobject (via its embedded
- *	kset) to @subsys.kset. This makes @obj a member of that 
- *	kset.
- */
-
-#define kset_set_kset_s(obj,subsys) \
-	(obj)->kset.kobj.kset = &(subsys)
-
-/**
- *	subsys_set_kset(obj,subsys) - set kset for subsystem
- *	@obj:		ptr to some object type.
- *	@_subsys:	a subsystem object (not a ptr).
- *
- *	Can be used for any object type with an embedded ->subsys.
- *	Sets the kset of @obj's kobject to @subsys.kset. This makes
- *	the object a member of that kset.
- */
-
-#define subsys_set_kset(obj,_subsys) \
-	(obj)->subsys.kobj.kset = &(_subsys)
-
-extern void subsystem_init(struct kset *);
 extern int __must_check subsystem_register(struct kset *);
 extern void subsystem_unregister(struct kset *);
 
-static inline struct kset *subsys_get(struct kset *s)
-{
-	if (s)
-		return kset_get(s);
-	return NULL;
-}
-
-static inline void subsys_put(struct kset *s)
-{
-	kset_put(s);
-}
-
 struct subsys_attribute {
 	struct attribute attr;
 	ssize_t (*show)(struct kset *, char *);
@@ -275,10 +237,11 @@
 int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
 			char *envp[]);
 
-int add_uevent_var(char **envp, int num_envp, int *cur_index,
-			char *buffer, int buffer_size, int *cur_len,
-			const char *format, ...)
-	__attribute__((format (printf, 7, 8)));
+int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...)
+	__attribute__((format (printf, 2, 3)));
+
+int kobject_action_type(const char *buf, size_t count,
+			enum kobject_action *type);
 #else
 static inline int kobject_uevent(struct kobject *kobj, enum kobject_action action)
 { return 0; }
@@ -287,10 +250,12 @@
 				      char *envp[])
 { return 0; }
 
-static inline int add_uevent_var(char **envp, int num_envp, int *cur_index,
-				      char *buffer, int buffer_size, int *cur_len, 
-				      const char *format, ...)
+static inline int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...)
 { return 0; }
+
+static inline int kobject_action_type(const char *buf, size_t count,
+			enum kobject_action *type)
+{ return -EINVAL; }
 #endif
 
 #endif /* __KERNEL__ */
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index c88234d..87439ad 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -2245,6 +2245,7 @@
 #define PCI_DEVICE_ID_INTEL_82801EB_5	0x24d5
 #define PCI_DEVICE_ID_INTEL_82801EB_6	0x24d6
 #define PCI_DEVICE_ID_INTEL_82801EB_11	0x24db
+#define PCI_DEVICE_ID_INTEL_82801EB_12	0x24dc
 #define PCI_DEVICE_ID_INTEL_82801EB_13	0x24dd
 #define PCI_DEVICE_ID_INTEL_ESB_1	0x25a1
 #define PCI_DEVICE_ID_INTEL_ESB_2	0x25a2
diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h
index 8bbd459..e808043 100644
--- a/include/linux/platform_device.h
+++ b/include/linux/platform_device.h
@@ -15,7 +15,7 @@
 
 struct platform_device {
 	const char	* name;
-	u32		id;
+	int		id;
 	struct device	dev;
 	u32		num_resources;
 	struct resource	* resource;
@@ -35,9 +35,10 @@
 extern int platform_get_irq_byname(struct platform_device *, char *);
 extern int platform_add_devices(struct platform_device **, int);
 
-extern struct platform_device *platform_device_register_simple(char *, unsigned int, struct resource *, unsigned int);
+extern struct platform_device *platform_device_register_simple(char *, int id,
+					struct resource *, unsigned int);
 
-extern struct platform_device *platform_device_alloc(const char *name, unsigned int id);
+extern struct platform_device *platform_device_alloc(const char *name, int id);
 extern int platform_device_add_resources(struct platform_device *pdev, struct resource *res, unsigned int num);
 extern int platform_device_add_data(struct platform_device *pdev, const void *data, size_t size);
 extern int platform_device_add(struct platform_device *pdev);
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index be8228e..149ab62 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -3,6 +3,8 @@
  *
  * Copyright (c) 2001,2002 Patrick Mochel
  * Copyright (c) 2004 Silicon Graphics, Inc.
+ * Copyright (c) 2007 SUSE Linux Products GmbH
+ * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
  *
  * Please see Documentation/filesystems/sysfs.txt for more information.
  */
@@ -17,23 +19,20 @@
 
 struct kobject;
 struct module;
-struct nameidata;
-struct dentry;
-struct sysfs_dirent;
 
 /* FIXME
  * The *owner field is no longer used, but leave around
  * until the tree gets cleaned up fully.
  */
 struct attribute {
-	const char		* name;
-	struct module		* owner;
+	const char		*name;
+	struct module		*owner;
 	mode_t			mode;
 };
 
 struct attribute_group {
-	const char		* name;
-	struct attribute	** attrs;
+	const char		*name;
+	struct attribute	**attrs;
 };
 
 
@@ -77,72 +76,41 @@
 	ssize_t	(*store)(struct kobject *,struct attribute *,const char *, size_t);
 };
 
-#define SYSFS_TYPE_MASK		0x00ff
-#define SYSFS_ROOT		0x0001
-#define SYSFS_DIR		0x0002
-#define SYSFS_KOBJ_ATTR 	0x0004
-#define SYSFS_KOBJ_BIN_ATTR	0x0008
-#define SYSFS_KOBJ_LINK 	0x0020
-#define SYSFS_COPY_NAME		(SYSFS_DIR | SYSFS_KOBJ_LINK)
-
-#define SYSFS_FLAG_MASK		~SYSFS_TYPE_MASK
-#define SYSFS_FLAG_REMOVED	0x0100
-
 #ifdef CONFIG_SYSFS
 
-extern int sysfs_schedule_callback(struct kobject *kobj,
-		void (*func)(void *), void *data, struct module *owner);
+int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *),
+			    void *data, struct module *owner);
 
-extern int __must_check
-sysfs_create_dir(struct kobject *kobj, struct sysfs_dirent *shadow_parent_sd);
+int __must_check sysfs_create_dir(struct kobject *kobj);
+void sysfs_remove_dir(struct kobject *kobj);
+int __must_check sysfs_rename_dir(struct kobject *kobj, const char *new_name);
+int __must_check sysfs_move_dir(struct kobject *kobj,
+				struct kobject *new_parent_kobj);
 
-extern void
-sysfs_remove_dir(struct kobject *);
-
-extern int __must_check
-sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,
-		 const char *new_name);
-
-extern int __must_check
-sysfs_move_dir(struct kobject *, struct kobject *);
-
-extern int __must_check
-sysfs_create_file(struct kobject *, const struct attribute *);
-
-extern int __must_check
-sysfs_update_file(struct kobject *, const struct attribute *);
-
-extern int __must_check
-sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode);
-
-extern void
-sysfs_remove_file(struct kobject *, const struct attribute *);
-
-extern int __must_check
-sysfs_create_link(struct kobject * kobj, struct kobject * target, const char * name);
-
-extern void
-sysfs_remove_link(struct kobject *, const char * name);
+int __must_check sysfs_create_file(struct kobject *kobj,
+				   const struct attribute *attr);
+int __must_check sysfs_chmod_file(struct kobject *kobj, struct attribute *attr,
+				  mode_t mode);
+void sysfs_remove_file(struct kobject *kobj, const struct attribute *attr);
 
 int __must_check sysfs_create_bin_file(struct kobject *kobj,
-					struct bin_attribute *attr);
+				       struct bin_attribute *attr);
 void sysfs_remove_bin_file(struct kobject *kobj, struct bin_attribute *attr);
 
-int __must_check sysfs_create_group(struct kobject *,
-					const struct attribute_group *);
-void sysfs_remove_group(struct kobject *, const struct attribute_group *);
+int __must_check sysfs_create_link(struct kobject *kobj, struct kobject *target,
+				   const char *name);
+void sysfs_remove_link(struct kobject *kobj, const char *name);
+
+int __must_check sysfs_create_group(struct kobject *kobj,
+				    const struct attribute_group *grp);
+void sysfs_remove_group(struct kobject *kobj,
+			const struct attribute_group *grp);
 int sysfs_add_file_to_group(struct kobject *kobj,
-		const struct attribute *attr, const char *group);
+			const struct attribute *attr, const char *group);
 void sysfs_remove_file_from_group(struct kobject *kobj,
-		const struct attribute *attr, const char *group);
+			const struct attribute *attr, const char *group);
 
-void sysfs_notify(struct kobject * k, char *dir, char *attr);
-
-
-extern int sysfs_make_shadowed_dir(struct kobject *kobj,
-	void * (*follow_link)(struct dentry *, struct nameidata *));
-extern struct sysfs_dirent *sysfs_create_shadow_dir(struct kobject *kobj);
-extern void sysfs_remove_shadow_dir(struct sysfs_dirent *shadow_sd);
+void sysfs_notify(struct kobject *kobj, char *dir, char *attr);
 
 extern int __must_check sysfs_init(void);
 
@@ -154,75 +122,76 @@
 	return -ENOSYS;
 }
 
-static inline int sysfs_create_dir(struct kobject *kobj,
-				   struct sysfs_dirent *shadow_parent_sd)
+static inline int sysfs_create_dir(struct kobject *kobj)
 {
 	return 0;
 }
 
-static inline void sysfs_remove_dir(struct kobject * k)
+static inline void sysfs_remove_dir(struct kobject *kobj)
 {
 	;
 }
 
-static inline int sysfs_rename_dir(struct kobject *kobj,
-				   struct sysfs_dirent *new_parent_sd,
-				   const char *new_name)
+static inline int sysfs_rename_dir(struct kobject *kobj, const char *new_name)
 {
 	return 0;
 }
 
-static inline int sysfs_move_dir(struct kobject * k, struct kobject * new_parent)
+static inline int sysfs_move_dir(struct kobject *kobj,
+				 struct kobject *new_parent_kobj)
 {
 	return 0;
 }
 
-static inline int sysfs_create_file(struct kobject * k, const struct attribute * a)
+static inline int sysfs_create_file(struct kobject *kobj,
+				    const struct attribute *attr)
 {
 	return 0;
 }
 
-static inline int sysfs_update_file(struct kobject * k, const struct attribute * a)
-{
-	return 0;
-}
-static inline int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode)
+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)
+static inline void sysfs_remove_file(struct kobject *kobj,
+				     const struct attribute *attr)
 {
 	;
 }
 
-static inline int sysfs_create_link(struct kobject * k, struct kobject * t, const char * n)
+static inline int sysfs_create_bin_file(struct kobject *kobj,
+					struct bin_attribute *attr)
 {
 	return 0;
 }
 
-static inline void sysfs_remove_link(struct kobject * k, const char * name)
+static inline int sysfs_remove_bin_file(struct kobject *kobj,
+					struct bin_attribute *attr)
+{
+	return 0;
+}
+
+static inline int sysfs_create_link(struct kobject *kobj,
+				    struct kobject *target, const char *name)
+{
+	return 0;
+}
+
+static inline void sysfs_remove_link(struct kobject *kobj, const char *name)
 {
 	;
 }
 
-
-static inline int sysfs_create_bin_file(struct kobject * k, struct bin_attribute * a)
+static inline int sysfs_create_group(struct kobject *kobj,
+				     const struct attribute_group *grp)
 {
 	return 0;
 }
 
-static inline int sysfs_remove_bin_file(struct kobject * k, struct bin_attribute * a)
-{
-	return 0;
-}
-
-static inline int sysfs_create_group(struct kobject * k, const struct attribute_group *g)
-{
-	return 0;
-}
-
-static inline void sysfs_remove_group(struct kobject * k, const struct attribute_group * g)
+static inline void sysfs_remove_group(struct kobject *kobj,
+				      const struct attribute_group *grp)
 {
 	;
 }
@@ -238,16 +207,10 @@
 {
 }
 
-static inline void sysfs_notify(struct kobject * k, char *dir, char *attr)
+static inline void sysfs_notify(struct kobject *kobj, char *dir, char *attr)
 {
 }
 
-static inline int sysfs_make_shadowed_dir(struct kobject *kobj,
-	void * (*follow_link)(struct dentry *, struct nameidata *))
-{
-	return 0;
-}
-
 static inline int __must_check sysfs_init(void)
 {
 	return 0;
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 6570719..60478f6 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -21,7 +21,6 @@
  * (Note: the *_driver.minor_start values 1, 64, 128, 192 are
  * hardcoded at present.)
  */
-#define NR_PTYS	CONFIG_LEGACY_PTY_COUNT   /* Number of legacy ptys */
 #define NR_UNIX98_PTY_DEFAULT	4096      /* Default maximum for Unix98 ptys */
 #define NR_UNIX98_PTY_MAX	(1 << MINORBITS) /* Absolute limit */
 #define NR_LDISCS		17
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 4f33a58f..c5c8f16 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -52,6 +52,7 @@
  * @ep_dev: ep_device for sysfs info
  * @extra: descriptors following this endpoint in the configuration
  * @extralen: how many bytes of "extra" are valid
+ * @enabled: URBs may be submitted to this endpoint
  *
  * USB requests are always queued to a given endpoint, identified by a
  * descriptor within an active interface in a given USB configuration.
@@ -64,6 +65,7 @@
 
 	unsigned char *extra;   /* Extra descriptors */
 	int extralen;
+	int enabled;
 };
 
 /* host-side wrapper for one interface setting's parsed descriptors */
@@ -344,6 +346,11 @@
  *
  * Usbcore drivers should not set usbdev->state directly.  Instead use
  * usb_set_device_state().
+ *
+ * @authorized: (user space) policy determines if we authorize this
+ *              device to be used or not. By default, wired USB
+ *              devices are authorized. WUSB devices are not, until we
+ *              authorize them from user space. FIXME -- complete doc
  */
 struct usb_device {
 	int		devnum;		/* Address on USB bus */
@@ -376,8 +383,11 @@
 	u8 portnum;			/* Parent port number (origin 1) */
 	u8 level;			/* Number of USB hub ancestors */
 
+	unsigned can_submit:1;		/* URBs may be submitted */
 	unsigned discon_suspended:1;	/* Disconnected while suspended */
 	unsigned have_langid:1;		/* whether string_langid is valid */
+	unsigned authorized:1;		/* Policy has determined we can use it */
+	unsigned wusb:1;		/* Device is Wireless USB */
 	int string_langid;		/* language ID for strings */
 
 	/* static strings from the device */
@@ -405,6 +415,7 @@
 
 	int pm_usage_cnt;		/* usage counter for autosuspend */
 	u32 quirks;			/* quirks of the whole device */
+	atomic_t urbnum;		/* number of URBs submitted for the whole device */
 
 #ifdef CONFIG_PM
 	struct delayed_work autosuspend; /* for delayed autosuspends */
@@ -419,6 +430,7 @@
 	unsigned persist_enabled:1;	/* USB_PERSIST enabled for this dev */
 	unsigned autosuspend_disabled:1; /* autosuspend and autoresume */
 	unsigned autoresume_disabled:1;  /*  disabled by the user */
+	unsigned skip_sys_resume:1;	/* skip the next system resume */
 #endif
 };
 #define	to_usb_device(d) container_of(d, struct usb_device, dev)
@@ -555,6 +567,29 @@
 /*-------------------------------------------------------------------------*/
 
 /**
+ * usb_endpoint_num - get the endpoint's number
+ * @epd: endpoint to be checked
+ *
+ * Returns @epd's number: 0 to 15.
+ */
+static inline int usb_endpoint_num(const struct usb_endpoint_descriptor *epd)
+{
+	return epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+}
+
+/**
+ * usb_endpoint_type - get the endpoint's transfer type
+ * @epd: endpoint to be checked
+ *
+ * Returns one of USB_ENDPOINT_XFER_{CONTROL, ISOC, BULK, INT} according
+ * to @epd's transfer type.
+ */
+static inline int usb_endpoint_type(const struct usb_endpoint_descriptor *epd)
+{
+	return epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+}
+
+/**
  * usb_endpoint_dir_in - check if the endpoint has IN direction
  * @epd: endpoint to be checked
  *
@@ -996,6 +1031,8 @@
 
 /*
  * urb->transfer_flags:
+ *
+ * Note: URB_DIR_IN/OUT is automatically set in usb_submit_urb().
  */
 #define URB_SHORT_NOT_OK	0x0001	/* report short reads as errors */
 #define URB_ISO_ASAP		0x0002	/* iso-only, urb->start_frame
@@ -1008,6 +1045,10 @@
 					 * needed */
 #define URB_FREE_BUFFER		0x0100	/* Free transfer buffer with the URB */
 
+#define URB_DIR_IN		0x0200	/* Transfer from device to host */
+#define URB_DIR_OUT		0
+#define URB_DIR_MASK		URB_DIR_IN
+
 struct usb_iso_packet_descriptor {
 	unsigned int offset;
 	unsigned int length;		/* expected length */
@@ -1037,6 +1078,8 @@
  * @urb_list: For use by current owner of the URB.
  * @anchor_list: membership in the list of an anchor
  * @anchor: to anchor URBs to a common mooring
+ * @ep: Points to the endpoint's data structure.  Will eventually
+ *	replace @pipe.
  * @pipe: Holds endpoint number, direction, type, and more.
  *	Create these values with the eight macros available;
  *	usb_{snd,rcv}TYPEpipe(dev,endpoint), where the TYPE is "ctrl"
@@ -1201,10 +1244,10 @@
 {
 	/* private: usb core and host controller only fields in the urb */
 	struct kref kref;		/* reference count of the URB */
-	spinlock_t lock;		/* lock for the URB */
 	void *hcpriv;			/* private data for host controller */
 	atomic_t use_count;		/* concurrent submissions counter */
 	u8 reject;			/* submissions will fail */
+	int unlinked;			/* unlink error code */
 
 	/* public: documented fields in the urb that can be used by drivers */
 	struct list_head urb_list;	/* list head for use by the urb's
@@ -1212,6 +1255,7 @@
 	struct list_head anchor_list;	/* the URB may be anchored by the driver */
 	struct usb_anchor *anchor;
 	struct usb_device *dev; 	/* (in) pointer to associated device */
+	struct usb_host_endpoint *ep;	/* (internal) pointer to endpoint struct */
 	unsigned int pipe;		/* (in) pipe information */
 	int status;			/* (return) non-ISO status */
 	unsigned int transfer_flags;	/* (in) URB_SHORT_NOT_OK | ...*/
@@ -1257,7 +1301,6 @@
 					 usb_complete_t complete_fn,
 					 void *context)
 {
-	spin_lock_init(&urb->lock);
 	urb->dev = dev;
 	urb->pipe = pipe;
 	urb->setup_packet = setup_packet;
@@ -1288,7 +1331,6 @@
 				      usb_complete_t complete_fn,
 				      void *context)
 {
-	spin_lock_init(&urb->lock);
 	urb->dev = dev;
 	urb->pipe = pipe;
 	urb->transfer_buffer = transfer_buffer;
@@ -1324,7 +1366,6 @@
 				     void *context,
 				     int interval)
 {
-	spin_lock_init(&urb->lock);
 	urb->dev = dev;
 	urb->pipe = pipe;
 	urb->transfer_buffer = transfer_buffer;
@@ -1352,6 +1393,30 @@
 extern int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor,
 					 unsigned int timeout);
 
+/**
+ * usb_urb_dir_in - check if an URB describes an IN transfer
+ * @urb: URB to be checked
+ *
+ * Returns 1 if @urb describes an IN transfer (device-to-host),
+ * otherwise 0.
+ */
+static inline int usb_urb_dir_in(struct urb *urb)
+{
+	return (urb->transfer_flags & URB_DIR_MASK) == URB_DIR_IN;
+}
+
+/**
+ * usb_urb_dir_out - check if an URB describes an OUT transfer
+ * @urb: URB to be checked
+ *
+ * Returns 1 if @urb describes an OUT transfer (host-to-device),
+ * otherwise 0.
+ */
+static inline int usb_urb_dir_out(struct urb *urb)
+{
+	return (urb->transfer_flags & URB_DIR_MASK) == URB_DIR_OUT;
+}
+
 void *usb_buffer_alloc (struct usb_device *dev, size_t size,
 	gfp_t mem_flags, dma_addr_t *dma);
 void usb_buffer_free (struct usb_device *dev, size_t size,
@@ -1364,13 +1429,13 @@
 #endif
 
 struct scatterlist;
-int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
+int usb_buffer_map_sg(const struct usb_device *dev, int is_in,
 		      struct scatterlist *sg, int nents);
 #if 0
-void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe,
+void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in,
 			   struct scatterlist *sg, int n_hw_ents);
 #endif
-void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe,
+void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in,
 			 struct scatterlist *sg, int n_hw_ents);
 
 /*-------------------------------------------------------------------*
diff --git a/include/linux/usb_gadget.h b/include/linux/usb/gadget.h
similarity index 92%
rename from include/linux/usb_gadget.h
rename to include/linux/usb/gadget.h
index 4f59b2a..46705e9 100644
--- a/include/linux/usb_gadget.h
+++ b/include/linux/usb/gadget.h
@@ -1,5 +1,5 @@
 /*
- * <linux/usb_gadget.h>
+ * <linux/usb/gadget.h>
  *
  * We call the USB code inside a Linux-based peripheral device a "gadget"
  * driver, except for the hardware-specific bus glue.  One USB host can
@@ -22,10 +22,10 @@
 /**
  * struct usb_request - describes one i/o request
  * @buf: Buffer used for data.  Always provide this; some controllers
- * 	only use PIO, or don't use DMA for some endpoints.
+ *	only use PIO, or don't use DMA for some endpoints.
  * @dma: DMA address corresponding to 'buf'.  If you don't set this
- * 	field, and the usb controller needs one, it is responsible
- * 	for mapping and unmapping the buffer.
+ *	field, and the usb controller needs one, it is responsible
+ *	for mapping and unmapping the buffer.
  * @length: Length of that data
  * @no_interrupt: If true, hints that no completion irq is needed.
  *	Helpful sometimes with deep request queues that are handled
@@ -45,16 +45,16 @@
  * @context: For use by the completion callback
  * @list: For use by the gadget driver.
  * @status: Reports completion code, zero or a negative errno.
- * 	Normally, faults block the transfer queue from advancing until
- * 	the completion callback returns.
- * 	Code "-ESHUTDOWN" indicates completion caused by device disconnect,
- * 	or when the driver disabled the endpoint.
+ *	Normally, faults block the transfer queue from advancing until
+ *	the completion callback returns.
+ *	Code "-ESHUTDOWN" indicates completion caused by device disconnect,
+ *	or when the driver disabled the endpoint.
  * @actual: Reports bytes transferred to/from the buffer.  For reads (OUT
- * 	transfers) this may be less than the requested length.  If the
- * 	short_not_ok flag is set, short reads are treated as errors
- * 	even when status otherwise indicates successful completion.
- * 	Note that for writes (IN transfers) some data bytes may still
- * 	reside in a device-side FIFO when the request is reported as
+ *	transfers) this may be less than the requested length.  If the
+ *	short_not_ok flag is set, short reads are treated as errors
+ *	even when status otherwise indicates successful completion.
+ *	Note that for writes (IN transfers) some data bytes may still
+ *	reside in a device-side FIFO when the request is reported as
  *	complete.
  *
  * These are allocated/freed through the endpoint they're used with.  The
@@ -128,7 +128,7 @@
  *	value can sometimes be reduced (hardware allowing), according to
  *      the endpoint descriptor used to configure the endpoint.
  * @driver_data:for use by the gadget driver.  all other fields are
- * 	read-only to gadget drivers.
+ *	read-only to gadget drivers.
  *
  * the bus controller driver lists all the general purpose endpoints in
  * gadget->ep_list.  the control endpoint (gadget->ep0) is not in that list,
@@ -148,10 +148,10 @@
 /**
  * usb_ep_enable - configure endpoint, making it usable
  * @ep:the endpoint being configured.  may not be the endpoint named "ep0".
- * 	drivers discover endpoints through the ep_list of a usb_gadget.
+ *	drivers discover endpoints through the ep_list of a usb_gadget.
  * @desc:descriptor for desired behavior.  caller guarantees this pointer
- * 	remains valid until the endpoint is disabled; the data byte order
- * 	is little-endian (usb-standard).
+ *	remains valid until the endpoint is disabled; the data byte order
+ *	is little-endian (usb-standard).
  *
  * when configurations are set, or when interface settings change, the driver
  * will enable or disable the relevant endpoints.  while it is enabled, an
@@ -232,7 +232,7 @@
  * @ep:the endpoint associated with the request
  * @req:the request being submitted
  * @gfp_flags: GFP_* flags to use in case the lower level driver couldn't
- * 	pre-allocate all necessary memory with the request.
+ *	pre-allocate all necessary memory with the request.
  *
  * This tells the device controller to perform the specified request through
  * that endpoint (reading or writing a buffer).  When the request completes,
@@ -415,7 +415,7 @@
  * struct usb_gadget - represents a usb slave device
  * @ops: Function pointers used to access hardware-specific operations.
  * @ep0: Endpoint zero, used when reading or writing responses to
- * 	driver setup() requests
+ *	driver setup() requests
  * @ep_list: List of other endpoints supported by the device.
  * @speed: Speed of current connection to USB host.
  * @is_dualspeed: True if the controller supports both high and full speed
@@ -432,7 +432,7 @@
  * @b_hnp_enable: OTG device feature flag, indicating that the A-Host
  *	enabled HNP support.
  * @name: Identifies the controller hardware type.  Used in diagnostics
- * 	and sometimes configuration.
+ *	and sometimes configuration.
  * @dev: Driver model state for this abstract device.
  *
  * Gadgets have a mostly-portable "gadget driver" implementing device
@@ -480,6 +480,39 @@
 
 
 /**
+ * gadget_is_dualspeed - return true iff the hardware handles high speed
+ * @gadget: controller that might support both high and full speeds
+ */
+static inline int gadget_is_dualspeed(struct usb_gadget *g)
+{
+#ifdef CONFIG_USB_GADGET_DUALSPEED
+	/* runtime test would check "g->is_dualspeed" ... that might be
+	 * useful to work around hardware bugs, but is mostly pointless
+	 */
+	return 1;
+#else
+	return 0;
+#endif
+}
+
+/**
+ * gadget_is_otg - return true iff the hardware is OTG-ready
+ * @gadget: controller that might have a Mini-AB connector
+ *
+ * This is a runtime test, since kernels with a USB-OTG stack sometimes
+ * run on boards which only have a Mini-B (or Mini-A) connector.
+ */
+static inline int gadget_is_otg(struct usb_gadget *g)
+{
+#ifdef CONFIG_USB_OTG
+	return g->is_otg;
+#else
+	return 0;
+#endif
+}
+
+
+/**
  * usb_gadget_frame_number - returns the current frame number
  * @gadget: controller that reports the frame number
  *
@@ -655,23 +688,23 @@
  * @function: String describing the gadget's function
  * @speed: Highest speed the driver handles.
  * @bind: Invoked when the driver is bound to a gadget, usually
- * 	after registering the driver.
- * 	At that point, ep0 is fully initialized, and ep_list holds
- * 	the currently-available endpoints.
- * 	Called in a context that permits sleeping.
+ *	after registering the driver.
+ *	At that point, ep0 is fully initialized, and ep_list holds
+ *	the currently-available endpoints.
+ *	Called in a context that permits sleeping.
  * @setup: Invoked for ep0 control requests that aren't handled by
- * 	the hardware level driver. Most calls must be handled by
- * 	the gadget driver, including descriptor and configuration
- * 	management.  The 16 bit members of the setup data are in
- * 	USB byte order. Called in_interrupt; this may not sleep.  Driver
+ *	the hardware level driver. Most calls must be handled by
+ *	the gadget driver, including descriptor and configuration
+ *	management.  The 16 bit members of the setup data are in
+ *	USB byte order. Called in_interrupt; this may not sleep.  Driver
  *	queues a response to ep0, or returns negative to stall.
  * @disconnect: Invoked after all transfers have been stopped,
- * 	when the host is disconnected.  May be called in_interrupt; this
- * 	may not sleep.  Some devices can't detect disconnect, so this might
+ *	when the host is disconnected.  May be called in_interrupt; this
+ *	may not sleep.  Some devices can't detect disconnect, so this might
  *	not be called except as part of controller shutdown.
  * @unbind: Invoked when the driver is unbound from a gadget,
- * 	usually from rmmod (after a disconnect is reported).
- * 	Called in a context that permits sleeping.
+ *	usually from rmmod (after a disconnect is reported).
+ *	Called in a context that permits sleeping.
  * @suspend: Invoked on USB suspend.  May be called in_interrupt.
  * @resume: Invoked on USB resume.  May be called in_interrupt.
  * @driver: Driver model state for this driver.
diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h
index 8da374c..2692ec9 100644
--- a/include/linux/usb/quirks.h
+++ b/include/linux/usb/quirks.h
@@ -4,11 +4,8 @@
  * belong here.
  */
 
-/* device must not be autosuspended */
-#define USB_QUIRK_NO_AUTOSUSPEND	0x00000001
-
 /* string descriptors must not be fetched using a 255-byte read */
-#define USB_QUIRK_STRING_FETCH_255	0x00000002
+#define USB_QUIRK_STRING_FETCH_255	0x00000001
 
 /* device can't resume correctly so reset it instead */
-#define USB_QUIRK_RESET_RESUME		0x00000004
+#define USB_QUIRK_RESET_RESUME		0x00000002
diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h
index e8b8928..488ce12 100644
--- a/include/linux/usb/serial.h
+++ b/include/linux/usb/serial.h
@@ -141,7 +141,7 @@
 };
 #define to_usb_serial(d) container_of(d, struct usb_serial, kref)
 
-#define NUM_DONT_CARE	(-1)
+#define NUM_DONT_CARE	99
 
 /* get and set the serial private data pointer helper functions */
 static inline void *usb_get_serial_data (struct usb_serial *serial)
@@ -160,12 +160,18 @@
  *	in the syslog messages when a device is inserted or removed.
  * @id_table: pointer to a list of usb_device_id structures that define all
  *	of the devices this structure can support.
- * @num_interrupt_in: the number of interrupt in endpoints this device will
- *	have.
- * @num_interrupt_out: the number of interrupt out endpoints this device will
- *	have.
- * @num_bulk_in: the number of bulk in endpoints this device will have.
- * @num_bulk_out: the number of bulk out endpoints this device will have.
+ * @num_interrupt_in: If a device doesn't have this many interrupt-in
+ *	endpoints, it won't be sent to the driver's attach() method.
+ *	(But it might still be sent to the probe() method.)
+ * @num_interrupt_out: If a device doesn't have this many interrupt-out
+ *	endpoints, it won't be sent to the driver's attach() method.
+ *	(But it might still be sent to the probe() method.)
+ * @num_bulk_in: If a device doesn't have this many bulk-in
+ *	endpoints, it won't be sent to the driver's attach() method.
+ *	(But it might still be sent to the probe() method.)
+ * @num_bulk_out: If a device doesn't have this many bulk-out
+ *	endpoints, it won't be sent to the driver's attach() method.
+ *	(But it might still be sent to the probe() method.)
  * @num_ports: the number of different ports this device will have.
  * @calc_num_ports: pointer to a function to determine how many ports this
  *	device has dynamically.  It will be called after the probe()
diff --git a/include/linux/usb_sl811.h b/include/linux/usb_sl811.h
deleted file mode 100644
index 4f2d012..0000000
--- a/include/linux/usb_sl811.h
+++ /dev/null
@@ -1,26 +0,0 @@
-
-/*
- * board initialization should put one of these into dev->platform_data
- * and place the sl811hs onto platform_bus named "sl811-hcd".
- */
-
-struct sl811_platform_data {
-	unsigned	can_wakeup:1;
-
-	/* given port_power, msec/2 after power on till power good */
-	u8		potpg;
-
-	/* mA/2 power supplied on this port (max = default = 250) */
-	u8		power;
-
-	/* sl811 relies on an external source of VBUS current */
-	void 		(*port_power)(struct device *dev, int is_on);
-
-	/* pulse sl811 nRST (probably with a GPIO) */
-	void 		(*reset)(struct device *dev);
-
-	// some boards need something like these:
- 	// int 		(*check_overcurrent)(struct device *dev);
- 	// void 	(*clock_enable)(struct device *dev, int is_on);
-};
-
diff --git a/include/linux/video_output.h b/include/linux/video_output.h
index e63e0c0..2fb46bc 100644
--- a/include/linux/video_output.h
+++ b/include/linux/video_output.h
@@ -31,9 +31,9 @@
 struct output_device {
 	int request_state;
 	struct output_properties *props;
-	struct class_device class_dev;
+	struct device dev;
 };
-#define to_output_device(obj) container_of(obj, struct output_device, class_dev)
+#define to_output_device(obj) container_of(obj, struct output_device, dev)
 struct output_device *video_output_register(const char *name,
 	struct device *dev,
 	void *devdata,
diff --git a/kernel/time/Kconfig b/kernel/time/Kconfig
index f663511..8d53106 100644
--- a/kernel/time/Kconfig
+++ b/kernel/time/Kconfig
@@ -23,3 +23,8 @@
 	  hardware is not capable then this option only increases
 	  the size of the kernel image.
 
+config GENERIC_CLOCKEVENTS_BUILD
+	bool
+	default y
+	depends on GENERIC_CLOCKEVENTS || GENERIC_CLOCKEVENTS_MIGR
+
diff --git a/kernel/time/Makefile b/kernel/time/Makefile
index 99b6034..905b0b5 100644
--- a/kernel/time/Makefile
+++ b/kernel/time/Makefile
@@ -1,6 +1,6 @@
 obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o
 
-obj-$(CONFIG_GENERIC_CLOCKEVENTS)		+= clockevents.o
+obj-$(CONFIG_GENERIC_CLOCKEVENTS_BUILD)		+= clockevents.o
 obj-$(CONFIG_GENERIC_CLOCKEVENTS)		+= tick-common.o
 obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)	+= tick-broadcast.o
 obj-$(CONFIG_TICK_ONESHOT)			+= tick-oneshot.o
diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c
index 41dd310..822beeb 100644
--- a/kernel/time/clockevents.c
+++ b/kernel/time/clockevents.c
@@ -194,6 +194,7 @@
 	local_irq_restore(flags);
 }
 
+#ifdef CONFIG_GENERIC_CLOCKEVENTS
 /**
  * clockevents_notify - notification about relevant events
  */
@@ -222,4 +223,4 @@
 	spin_unlock(&clockevents_lock);
 }
 EXPORT_SYMBOL_GPL(clockevents_notify);
-
+#endif
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c
index 0962e05..298bc7c 100644
--- a/kernel/time/tick-broadcast.c
+++ b/kernel/time/tick-broadcast.c
@@ -64,8 +64,9 @@
  */
 int tick_check_broadcast_device(struct clock_event_device *dev)
 {
-	if (tick_broadcast_device.evtdev ||
-	    (dev->features & CLOCK_EVT_FEAT_C3STOP))
+	if ((tick_broadcast_device.evtdev &&
+	     tick_broadcast_device.evtdev->rating >= dev->rating) ||
+	     (dev->features & CLOCK_EVT_FEAT_C3STOP))
 		return 0;
 
 	clockevents_exchange_device(NULL, dev);
@@ -176,8 +177,6 @@
  */
 static void tick_handle_periodic_broadcast(struct clock_event_device *dev)
 {
-	dev->next_event.tv64 = KTIME_MAX;
-
 	tick_do_periodic_broadcast();
 
 	/*
@@ -515,11 +514,9 @@
  */
 void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
 {
-	if (bc->mode != CLOCK_EVT_MODE_ONESHOT) {
-		bc->event_handler = tick_handle_oneshot_broadcast;
-		clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT);
-		bc->next_event.tv64 = KTIME_MAX;
-	}
+	bc->event_handler = tick_handle_oneshot_broadcast;
+	clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT);
+	bc->next_event.tv64 = KTIME_MAX;
 }
 
 /*
diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c
index 77a21ab..3f3ae39 100644
--- a/kernel/time/tick-common.c
+++ b/kernel/time/tick-common.c
@@ -200,7 +200,7 @@
 
 	cpu = smp_processor_id();
 	if (!cpu_isset(cpu, newdev->cpumask))
-		goto out;
+		goto out_bc;
 
 	td = &per_cpu(tick_cpu_device, cpu);
 	curdev = td->evtdev;
@@ -265,7 +265,7 @@
 	 */
 	if (tick_check_broadcast_device(newdev))
 		ret = NOTIFY_STOP;
-out:
+
 	spin_unlock_irqrestore(&tick_device_lock, flags);
 
 	return ret;
diff --git a/lib/Makefile b/lib/Makefile
index 4f3f3e2..6c4ea33 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -10,7 +10,7 @@
 lib-$(CONFIG_MMU) += ioremap.o
 lib-$(CONFIG_SMP) += cpumask.o
 
-lib-y	+= kobject.o kref.o kobject_uevent.o klist.o
+lib-y	+= kobject.o kref.o klist.o
 
 obj-y += div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
 	 bust_spinlocks.o hexdump.o kasprintf.o
@@ -20,6 +20,7 @@
 CFLAGS_kobject_uevent.o += -DDEBUG
 endif
 
+lib-$(CONFIG_HOTPLUG) += kobject_uevent.o
 obj-$(CONFIG_GENERIC_IOMAP) += iomap.o
 obj-$(CONFIG_HAS_IOMEM) += iomap_copy.o devres.o
 obj-$(CONFIG_CHECK_SIGNATURE) += check_signature.o
diff --git a/lib/kobject.c b/lib/kobject.c
index 4b08e0f..03d4036 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -2,6 +2,8 @@
  * kobject.c - library routines for handling generic kernel objects
  *
  * Copyright (c) 2002-2003 Patrick Mochel <mochel@osdl.org>
+ * Copyright (c) 2006-2007 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (c) 2006-2007 Novell Inc.
  *
  * This file is released under the GPLv2.
  *
@@ -44,11 +46,11 @@
 	return error;
 }
 
-static int create_dir(struct kobject *kobj, struct sysfs_dirent *shadow_parent)
+static int create_dir(struct kobject * kobj)
 {
 	int error = 0;
 	if (kobject_name(kobj)) {
-		error = sysfs_create_dir(kobj, shadow_parent);
+		error = sysfs_create_dir(kobj);
 		if (!error) {
 			if ((error = populate_dir(kobj)))
 				sysfs_remove_dir(kobj);
@@ -131,7 +133,6 @@
 		return;
 	kref_init(&kobj->kref);
 	INIT_LIST_HEAD(&kobj->entry);
-	init_waitqueue_head(&kobj->poll);
 	kobj->kset = kset_get(kobj->kset);
 }
 
@@ -157,12 +158,11 @@
 }
 
 /**
- *	kobject_shadow_add - add an object to the hierarchy.
+ *	kobject_add - add an object to the hierarchy.
  *	@kobj:	object.
- *	@shadow_parent: sysfs directory to add to.
  */
 
-int kobject_shadow_add(struct kobject *kobj, struct sysfs_dirent *shadow_parent)
+int kobject_add(struct kobject * kobj)
 {
 	int error = 0;
 	struct kobject * parent;
@@ -170,7 +170,7 @@
 	if (!(kobj = kobject_get(kobj)))
 		return -ENOENT;
 	if (!kobj->k_name)
-		kobj->k_name = kobj->name;
+		kobject_set_name(kobj, "NO_NAME");
 	if (!*kobj->k_name) {
 		pr_debug("kobject attempted to be registered with no name!\n");
 		WARN_ON(1);
@@ -181,7 +181,7 @@
 
 	pr_debug("kobject %s: registering. parent: %s, set: %s\n",
 		 kobject_name(kobj), parent ? kobject_name(parent) : "<NULL>", 
-		 kobj->kset ? kobj->kset->kobj.name : "<NULL>" );
+		 kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>" );
 
 	if (kobj->kset) {
 		spin_lock(&kobj->kset->list_lock);
@@ -194,7 +194,7 @@
 		kobj->parent = parent;
 	}
 
-	error = create_dir(kobj, shadow_parent);
+	error = create_dir(kobj);
 	if (error) {
 		/* unlink does the kobject_put() for us */
 		unlink(kobj);
@@ -216,16 +216,6 @@
 }
 
 /**
- *	kobject_add - add an object to the hierarchy.
- *	@kobj:	object.
- */
-int kobject_add(struct kobject * kobj)
-{
-	return kobject_shadow_add(kobj, NULL);
-}
-
-
-/**
  *	kobject_register - initialize and add an object.
  *	@kobj:	object in question.
  */
@@ -255,54 +245,50 @@
 int kobject_set_name(struct kobject * kobj, const char * fmt, ...)
 {
 	int error = 0;
-	int limit = KOBJ_NAME_LEN;
+	int limit;
 	int need;
 	va_list args;
-	char * name;
+	char *name;
 
-	/* 
-	 * First, try the static array 
-	 */
-	va_start(args,fmt);
-	need = vsnprintf(kobj->name,limit,fmt,args);
+	/* find out how big a buffer we need */
+	name = kmalloc(1024, GFP_KERNEL);
+	if (!name) {
+		error = -ENOMEM;
+		goto done;
+	}
+	va_start(args, fmt);
+	need = vsnprintf(name, 1024, fmt, args);
 	va_end(args);
-	if (need < limit) 
-		name = kobj->name;
-	else {
-		/* 
-		 * Need more space? Allocate it and try again 
-		 */
-		limit = need + 1;
-		name = kmalloc(limit,GFP_KERNEL);
-		if (!name) {
-			error = -ENOMEM;
-			goto Done;
-		}
-		va_start(args,fmt);
-		need = vsnprintf(name,limit,fmt,args);
-		va_end(args);
+	kfree(name);
 
-		/* Still? Give up. */
-		if (need >= limit) {
-			kfree(name);
-			error = -EFAULT;
-			goto Done;
-		}
+	/* Allocate the new space and copy the string in */
+	limit = need + 1;
+	name = kmalloc(limit, GFP_KERNEL);
+	if (!name) {
+		error = -ENOMEM;
+		goto done;
+	}
+	va_start(args, fmt);
+	need = vsnprintf(name, limit, fmt, args);
+	va_end(args);
+
+	/* something wrong with the string we copied? */
+	if (need >= limit) {
+		kfree(name);
+		error = -EFAULT;
+		goto done;
 	}
 
 	/* Free the old name, if necessary. */
-	if (kobj->k_name && kobj->k_name != kobj->name)
-		kfree(kobj->k_name);
+	kfree(kobj->k_name);
 
 	/* Now, set the new name */
 	kobj->k_name = name;
- Done:
+done:
 	return error;
 }
-
 EXPORT_SYMBOL(kobject_set_name);
 
-
 /**
  *	kobject_rename - change the name of an object
  *	@kobj:	object in question.
@@ -338,7 +324,7 @@
 	/* Note : if we want to send the new name alone, not the full path,
 	 * we could probably use kobject_name(kobj); */
 
-	error = sysfs_rename_dir(kobj, kobj->parent->sd, new_name);
+	error = sysfs_rename_dir(kobj, new_name);
 
 	/* This function is mostly/only used for network interface.
 	 * Some hotplug package track interfaces by their name and
@@ -355,27 +341,6 @@
 }
 
 /**
- *	kobject_rename - change the name of an object
- *	@kobj:	object in question.
- *	@new_parent: object's new parent
- *	@new_name: object's new name
- */
-
-int kobject_shadow_rename(struct kobject *kobj,
-			  struct sysfs_dirent *new_parent, const char *new_name)
-{
-	int error = 0;
-
-	kobj = kobject_get(kobj);
-	if (!kobj)
-		return -EINVAL;
-	error = sysfs_rename_dir(kobj, new_parent, new_name);
-	kobject_put(kobj);
-
-	return error;
-}
-
-/**
  *	kobject_move - move object to another parent
  *	@kobj:	object in question.
  *	@new_parent: object's new parent (can be NULL)
@@ -477,13 +442,16 @@
 	struct kobj_type * t = get_ktype(kobj);
 	struct kset * s = kobj->kset;
 	struct kobject * parent = kobj->parent;
+	const char *name = kobj->k_name;
 
 	pr_debug("kobject %s: cleaning up\n",kobject_name(kobj));
-	if (kobj->k_name != kobj->name)
-		kfree(kobj->k_name);
-	kobj->k_name = NULL;
-	if (t && t->release)
+	if (t && t->release) {
 		t->release(kobj);
+		/* If we have a release function, we can guess that this was
+		 * not a statically allocated kobject, so we should be safe to
+		 * free the name */
+		kfree(name);
+	}
 	if (s)
 		kset_put(s);
 	kobject_put(parent);
@@ -651,11 +619,6 @@
 	return ret;
 }
 
-void subsystem_init(struct kset *s)
-{
-	kset_init(s);
-}
-
 int subsystem_register(struct kset *s)
 {
 	return kset_register(s);
@@ -679,9 +642,9 @@
 	if (!s || !a)
 		return -EINVAL;
 
-	if (subsys_get(s)) {
+	if (kset_get(s)) {
 		error = sysfs_create_file(&s->kobj, &a->attr);
-		subsys_put(s);
+		kset_put(s);
 	}
 	return error;
 }
diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c
index e06a8dc..2e4eae5 100644
--- a/lib/kobject_uevent.c
+++ b/lib/kobject_uevent.c
@@ -22,31 +22,62 @@
 #include <linux/kobject.h>
 #include <net/sock.h>
 
-#define BUFFER_SIZE	2048	/* buffer for the variables */
-#define NUM_ENVP	32	/* number of env pointers */
 
-/* the strings here must match the enum in include/linux/kobject.h */
-const char *kobject_actions[] = {
-	"add",
-	"remove",
-	"change",
-	"move",
-	"online",
-	"offline",
-};
-
-#if defined(CONFIG_HOTPLUG)
 u64 uevent_seqnum;
-char uevent_helper[UEVENT_HELPER_PATH_LEN] = "/sbin/hotplug";
+char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH;
 static DEFINE_SPINLOCK(sequence_lock);
 #if defined(CONFIG_NET)
 static struct sock *uevent_sock;
 #endif
 
+/* the strings here must match the enum in include/linux/kobject.h */
+static const char *kobject_actions[] = {
+	[KOBJ_ADD] =		"add",
+	[KOBJ_REMOVE] =		"remove",
+	[KOBJ_CHANGE] =		"change",
+	[KOBJ_MOVE] =		"move",
+	[KOBJ_ONLINE] =		"online",
+	[KOBJ_OFFLINE] =	"offline",
+};
+
+/**
+ * kobject_action_type - translate action string to numeric type
+ *
+ * @buf: buffer containing the action string, newline is ignored
+ * @len: length of buffer
+ * @type: pointer to the location to store the action type
+ *
+ * Returns 0 if the action string was recognized.
+ */
+int kobject_action_type(const char *buf, size_t count,
+			enum kobject_action *type)
+{
+	enum kobject_action action;
+	int ret = -EINVAL;
+
+	if (count && buf[count-1] == '\n')
+		count--;
+
+	if (!count)
+		goto out;
+
+	for (action = 0; action < ARRAY_SIZE(kobject_actions); action++) {
+		if (strncmp(kobject_actions[action], buf, count) != 0)
+			continue;
+		if (kobject_actions[action][count] != '\0')
+			continue;
+		*type = action;
+		ret = 0;
+		break;
+	}
+out:
+	return ret;
+}
+
 /**
  * kobject_uevent_env - send an uevent with environmental data
  *
- * @action: action that is happening (usually KOBJ_MOVE)
+ * @action: action that is happening
  * @kobj: struct kobject that the action is happening to
  * @envp_ext: pointer to environmental data
  *
@@ -54,36 +85,26 @@
  * corresponding error when it fails.
  */
 int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
-			char *envp_ext[])
+		       char *envp_ext[])
 {
-	char **envp;
-	char *buffer;
-	char *scratch;
-	const char *action_string;
+	struct kobj_uevent_env *env;
+	const char *action_string = kobject_actions[action];
 	const char *devpath = NULL;
 	const char *subsystem;
 	struct kobject *top_kobj;
 	struct kset *kset;
 	struct kset_uevent_ops *uevent_ops;
 	u64 seq;
-	char *seq_buff;
 	int i = 0;
 	int retval = 0;
-	int j;
 
 	pr_debug("%s\n", __FUNCTION__);
 
-	action_string = kobject_actions[action];
-	if (!action_string) {
-		pr_debug("kobject attempted to send uevent without action_string!\n");
-		return -EINVAL;
-	}
-
 	/* search the kset we belong to */
 	top_kobj = kobj;
-	while (!top_kobj->kset && top_kobj->parent) {
+	while (!top_kobj->kset && top_kobj->parent)
 		top_kobj = top_kobj->parent;
-	}
+
 	if (!top_kobj->kset) {
 		pr_debug("kobject attempted to send uevent without kset!\n");
 		return -EINVAL;
@@ -92,7 +113,7 @@
 	kset = top_kobj->kset;
 	uevent_ops = kset->uevent_ops;
 
-	/*  skip the event, if the filter returns zero. */
+	/* skip the event, if the filter returns zero. */
 	if (uevent_ops && uevent_ops->filter)
 		if (!uevent_ops->filter(kset, kobj)) {
 			pr_debug("kobject filter function caused the event to drop!\n");
@@ -109,18 +130,11 @@
 		return 0;
 	}
 
-	/* environment index */
-	envp = kzalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL);
-	if (!envp)
+	/* environment buffer */
+	env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
+	if (!env)
 		return -ENOMEM;
 
-	/* environment values */
-	buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL);
-	if (!buffer) {
-		retval = -ENOMEM;
-		goto exit;
-	}
-
 	/* complete object path */
 	devpath = kobject_get_path(kobj, GFP_KERNEL);
 	if (!devpath) {
@@ -128,29 +142,29 @@
 		goto exit;
 	}
 
-	/* event environemnt for helper process only */
-	envp[i++] = "HOME=/";
-	envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
-
 	/* default keys */
-	scratch = buffer;
-	envp [i++] = scratch;
-	scratch += sprintf(scratch, "ACTION=%s", action_string) + 1;
-	envp [i++] = scratch;
-	scratch += sprintf (scratch, "DEVPATH=%s", devpath) + 1;
-	envp [i++] = scratch;
-	scratch += sprintf(scratch, "SUBSYSTEM=%s", subsystem) + 1;
-	for (j = 0; envp_ext && envp_ext[j]; j++)
-		envp[i++] = envp_ext[j];
-	/* just reserve the space, overwrite it after kset call has returned */
-	envp[i++] = seq_buff = scratch;
-	scratch += strlen("SEQNUM=18446744073709551616") + 1;
+	retval = add_uevent_var(env, "ACTION=%s", action_string);
+	if (retval)
+		goto exit;
+	retval = add_uevent_var(env, "DEVPATH=%s", devpath);
+	if (retval)
+		goto exit;
+	retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem);
+	if (retval)
+		goto exit;
+
+	/* keys passed in from the caller */
+	if (envp_ext) {
+		for (i = 0; envp_ext[i]; i++) {
+			retval = add_uevent_var(env, envp_ext[i]);
+			if (retval)
+				goto exit;
+		}
+	}
 
 	/* let the kset specific function add its stuff */
 	if (uevent_ops && uevent_ops->uevent) {
-		retval = uevent_ops->uevent(kset, kobj,
-				  &envp[i], NUM_ENVP - i, scratch,
-				  BUFFER_SIZE - (scratch - buffer));
+		retval = uevent_ops->uevent(kset, kobj, env);
 		if (retval) {
 			pr_debug ("%s - uevent() returned %d\n",
 				  __FUNCTION__, retval);
@@ -158,11 +172,13 @@
 		}
 	}
 
-	/* we will send an event, request a new sequence number */
+	/* we will send an event, so request a new sequence number */
 	spin_lock(&sequence_lock);
 	seq = ++uevent_seqnum;
 	spin_unlock(&sequence_lock);
-	sprintf(seq_buff, "SEQNUM=%llu", (unsigned long long)seq);
+	retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)seq);
+	if (retval)
+		goto exit;
 
 #if defined(CONFIG_NET)
 	/* send netlink message */
@@ -172,17 +188,19 @@
 
 		/* allocate message with the maximum possible size */
 		len = strlen(action_string) + strlen(devpath) + 2;
-		skb = alloc_skb(len + BUFFER_SIZE, GFP_KERNEL);
+		skb = alloc_skb(len + env->buflen, GFP_KERNEL);
 		if (skb) {
+			char *scratch;
+
 			/* add header */
 			scratch = skb_put(skb, len);
 			sprintf(scratch, "%s@%s", action_string, devpath);
 
 			/* copy keys to our continuous event payload buffer */
-			for (i = 2; envp[i]; i++) {
-				len = strlen(envp[i]) + 1;
+			for (i = 0; i < env->envp_idx; i++) {
+				len = strlen(env->envp[i]) + 1;
 				scratch = skb_put(skb, len);
-				strcpy(scratch, envp[i]);
+				strcpy(scratch, env->envp[i]);
 			}
 
 			NETLINK_CB(skb).dst_group = 1;
@@ -198,13 +216,19 @@
 		argv [0] = uevent_helper;
 		argv [1] = (char *)subsystem;
 		argv [2] = NULL;
-		call_usermodehelper (argv[0], argv, envp, UMH_WAIT_EXEC);
+		retval = add_uevent_var(env, "HOME=/");
+		if (retval)
+			goto exit;
+		retval = add_uevent_var(env, "PATH=/sbin:/bin:/usr/sbin:/usr/bin");
+		if (retval)
+			goto exit;
+
+		call_usermodehelper (argv[0], argv, env->envp, UMH_WAIT_EXEC);
 	}
 
 exit:
 	kfree(devpath);
-	kfree(buffer);
-	kfree(envp);
+	kfree(env);
 	return retval;
 }
 
@@ -213,7 +237,7 @@
 /**
  * kobject_uevent - notify userspace by ending an uevent
  *
- * @action: action that is happening (usually KOBJ_ADD and KOBJ_REMOVE)
+ * @action: action that is happening
  * @kobj: struct kobject that the action is happening to
  *
  * Returns 0 if kobject_uevent() is completed with success or the
@@ -227,52 +251,38 @@
 EXPORT_SYMBOL_GPL(kobject_uevent);
 
 /**
- * add_uevent_var - helper for creating event variables
- * @envp: Pointer to table of environment variables, as passed into
- * uevent() method.
- * @num_envp: Number of environment variable slots available, as
- * passed into uevent() method.
- * @cur_index: Pointer to current index into @envp.  It should be
- * initialized to 0 before the first call to add_uevent_var(),
- * and will be incremented on success.
- * @buffer: Pointer to buffer for environment variables, as passed
- * into uevent() method.
- * @buffer_size: Length of @buffer, as passed into uevent() method.
- * @cur_len: Pointer to current length of space used in @buffer.
- * Should be initialized to 0 before the first call to
- * add_uevent_var(), and will be incremented on success.
- * @format: Format for creating environment variable (of the form
- * "XXX=%x") for snprintf().
+ * add_uevent_var - add key value string to the environment buffer
+ * @env: environment buffer structure
+ * @format: printf format for the key=value pair
  *
  * Returns 0 if environment variable was added successfully or -ENOMEM
  * if no space was available.
  */
-int add_uevent_var(char **envp, int num_envp, int *cur_index,
-		   char *buffer, int buffer_size, int *cur_len,
-		   const char *format, ...)
+int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...)
 {
 	va_list args;
+	int len;
 
-	/*
-	 * We check against num_envp - 1 to make sure there is at
-	 * least one slot left after we return, since kobject_uevent()
-	 * needs to set the last slot to NULL.
-	 */
-	if (*cur_index >= num_envp - 1)
+	if (env->envp_idx >= ARRAY_SIZE(env->envp)) {
+		printk(KERN_ERR "add_uevent_var: too many keys\n");
+		WARN_ON(1);
 		return -ENOMEM;
-
-	envp[*cur_index] = buffer + *cur_len;
+	}
 
 	va_start(args, format);
-	*cur_len += vsnprintf(envp[*cur_index],
-			      max(buffer_size - *cur_len, 0),
-			      format, args) + 1;
+	len = vsnprintf(&env->buf[env->buflen],
+			sizeof(env->buf) - env->buflen,
+			format, args);
 	va_end(args);
 
-	if (*cur_len > buffer_size)
+	if (len >= (sizeof(env->buf) - env->buflen)) {
+		printk(KERN_ERR "add_uevent_var: buffer size too small\n");
+		WARN_ON(1);
 		return -ENOMEM;
+	}
 
-	(*cur_index)++;
+	env->envp[env->envp_idx++] = &env->buf[env->buflen];
+	env->buflen += len + 1;
 	return 0;
 }
 EXPORT_SYMBOL_GPL(add_uevent_var);
@@ -293,5 +303,3 @@
 
 postcore_initcall(kobject_uevent_init);
 #endif
-
-#endif /* CONFIG_HOTPLUG */
diff --git a/net/atm/atm_sysfs.c b/net/atm/atm_sysfs.c
index f094a08..9ef07ed 100644
--- a/net/atm/atm_sysfs.c
+++ b/net/atm/atm_sysfs.c
@@ -105,10 +105,9 @@
 	NULL
 };
 
-static int atm_uevent(struct class_device *cdev, char **envp, int num_envp, char *buf, int size)
+static int atm_uevent(struct class_device *cdev, struct kobj_uevent_env *env)
 {
 	struct atm_dev *adev;
-	int i = 0, len = 0;
 
 	if (!cdev)
 		return -ENODEV;
@@ -117,11 +116,9 @@
 	if (!adev)
 		return -ENODEV;
 
-	if (add_uevent_var(envp, num_envp, &i, buf, size, &len,
-			   "NAME=%s%d", adev->type, adev->number))
+	if (add_uevent_var(env, "NAME=%s%d", adev->type, adev->number))
 		return -ENOMEM;
 
-	envp[i] = NULL;
 	return 0;
 }
 
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c
index c65f54e..3312e8f 100644
--- a/net/bridge/br_sysfs_br.c
+++ b/net/bridge/br_sysfs_br.c
@@ -435,7 +435,7 @@
 	err = kobject_register(&br->ifobj);
 	if (err) {
 		pr_info("%s: can't add kobject (directory) %s/%s\n",
-			__FUNCTION__, dev->name, br->ifobj.name);
+			__FUNCTION__, dev->name, kobject_name(&br->ifobj));
 		goto out3;
 	}
 	return 0;
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index 909a03d..6628e45 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -396,28 +396,22 @@
 #endif /* CONFIG_SYSFS */
 
 #ifdef CONFIG_HOTPLUG
-static int netdev_uevent(struct device *d, char **envp,
-			 int num_envp, char *buf, int size)
+static int netdev_uevent(struct device *d, struct kobj_uevent_env *env)
 {
 	struct net_device *dev = to_net_dev(d);
-	int retval, len = 0, i = 0;
+	int retval;
 
 	/* pass interface to uevent. */
-	retval = add_uevent_var(envp, num_envp, &i,
-				buf, size, &len,
-				"INTERFACE=%s", dev->name);
+	retval = add_uevent_var(env, "INTERFACE=%s", dev->name);
 	if (retval)
 		goto exit;
 
 	/* pass ifindex to uevent.
 	 * ifindex is useful as it won't change (interface name may change)
 	 * and is what RtNetlink uses natively. */
-	retval = add_uevent_var(envp, num_envp, &i,
-				buf, size, &len,
-				"IFINDEX=%d", dev->ifindex);
+	retval = add_uevent_var(env, "IFINDEX=%d", dev->ifindex);
 
 exit:
-	envp[i] = NULL;
 	return retval;
 }
 #endif
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c
index 2d5d225..29f820e 100644
--- a/net/wireless/sysfs.c
+++ b/net/wireless/sysfs.c
@@ -53,8 +53,7 @@
 }
 
 #ifdef CONFIG_HOTPLUG
-static int wiphy_uevent(struct device *dev, char **envp,
-			int num_envp, char *buf, int size)
+static int wiphy_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	/* TODO, we probably need stuff here */
 	return 0;
diff --git a/sound/aoa/soundbus/core.c b/sound/aoa/soundbus/core.c
index 64d1639..f84f3e5 100644
--- a/sound/aoa/soundbus/core.c
+++ b/sound/aoa/soundbus/core.c
@@ -56,13 +56,12 @@
 }
 
 
-static int soundbus_uevent(struct device *dev, char **envp, int num_envp,
-			   char *buffer, int buffer_size)
+static int soundbus_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct soundbus_dev * soundbus_dev;
 	struct of_device * of;
 	const char *compat;
-	int retval = 0, i = 0, length = 0;
+	int retval = 0;
 	int cplen, seen = 0;
 
 	if (!dev)
@@ -75,15 +74,11 @@
 	of = &soundbus_dev->ofdev;
 
 	/* stuff we want to pass to /sbin/hotplug */
-	retval = add_uevent_var(envp, num_envp, &i,
-				buffer, buffer_size, &length,
-				"OF_NAME=%s", of->node->name);
+	retval = add_uevent_var(env, "OF_NAME=%s", of->node->name);
 	if (retval)
 		return retval;
 
-	retval = add_uevent_var(envp, num_envp, &i,
-				buffer, buffer_size, &length,
-				"OF_TYPE=%s", of->node->type);
+	retval = add_uevent_var(env, "OF_TYPE=%s", of->node->type);
 	if (retval)
 		return retval;
 
@@ -93,27 +88,19 @@
 
 	compat = of_get_property(of->node, "compatible", &cplen);
 	while (compat && cplen > 0) {
-		int tmp = length;
-		retval = add_uevent_var(envp, num_envp, &i,
-					buffer, buffer_size, &length,
-					"OF_COMPATIBLE_%d=%s", seen, compat);
+		int tmp = env->buflen;
+		retval = add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat);
 		if (retval)
 			return retval;
-		compat += length - tmp;
-		cplen -= length - tmp;
+		compat += env->buflen - tmp;
+		cplen -= env->buflen - tmp;
 		seen += 1;
 	}
 
-	retval = add_uevent_var(envp, num_envp, &i,
-				buffer, buffer_size, &length,
-				"OF_COMPATIBLE_N=%d", seen);
+	retval = add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen);
 	if (retval)
 		return retval;
-	retval = add_uevent_var(envp, num_envp, &i,
-				buffer, buffer_size, &length,
-				"MODALIAS=%s", soundbus_dev->modalias);
-
-	envp[i] = NULL;
+	retval = add_uevent_var(env, "MODALIAS=%s", soundbus_dev->modalias);
 
 	return retval;
 }