Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 21 Aug 2008 20:48:37 +0000 (13:48 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 21 Aug 2008 20:48:37 +0000 (13:48 -0700)
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6:
  pnp: fix "add acpi:* modalias entries"
  UIO: generic irq handling for some uio platform devices
  UIO: uio_pdrv: fix license specification
  UIO: uio_pdrv: fix memory leak
  block: drop references taken by class_find_device()
  block: fix partial read() of /proc/{partitions,diskstats}
  PM: Remove WARN_ON from device_pm_add
  driver core: add init_name to struct device
  PM: don't skip device PM init when CONFIG_PM_SLEEP isn't set and CONFIG_PM is set
  driver model: anti-oopsing medicine
  dev_printk(): constify the `dev' argument
  drivers/base/driver.c: remove unused to_dev() macro
  Documentation: HOWTO-ja_JP-sync patch
  Japanese translation of Documentation/SubmitChecklist
  kobject: Replace ALL occurrences of '/' with '!' instead of only the first one.

15 files changed:
Documentation/ja_JP/HOWTO
Documentation/ja_JP/SubmitChecklist [new file with mode: 0644]
block/genhd.c
drivers/base/class.c
drivers/base/core.c
drivers/base/driver.c
drivers/base/power/main.c
drivers/base/power/power.h
drivers/uio/Kconfig
drivers/uio/Makefile
drivers/uio/uio_pdrv.c
drivers/uio/uio_pdrv_genirq.c [new file with mode: 0644]
include/linux/device.h
lib/kobject.c
scripts/mod/file2alias.c

index 488c77f..0775cf4 100644 (file)
@@ -11,14 +11,14 @@ for non English (read: Japanese) speakers and is not intended as a
 fork. So if you have any comments or updates for this file, please try
 to update the original English file first.
 
-Last Updated: 2007/11/16
+Last Updated: 2008/08/21
 ==================================
 これは、
-linux-2.6.24/Documentation/HOWTO
+linux-2.6.27/Documentation/HOWTO
 の和訳です。
 
 翻訳団体: JF プロジェクト < http://www.linux.or.jp/JF/ >
-翻訳日: 2007/11/10
+翻訳日: 2008/8/5
 翻訳者: 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>
@@ -287,13 +287,15 @@ Linux カーネルの開発プロセスは現在幾つかの異なるメイン
     に安定した状態にあると判断したときにリリースされます。目標は毎週新
     しい -rc カーネルをリリースすることです。
 
-   - 以下の URL で各 -rc リリースに存在する既知の後戻り問題のリスト
-     が追跡されます-
-     http://kernelnewbies.org/known_regressions
-
   - このプロセスはカーネルが 「準備ができた」と考えられるまで継続しま
     す。このプロセスはだいたい 6週間継続します。
 
+  - 各リリースでの既知の後戻り問題(regression: このリリースの中で新規
+    に作り込まれた問題を指す) はその都度 Linux-kernel メーリングリスト
+    に投稿されます。ゴールとしては、カーネルが 「準備ができた」と宣言
+    する前にこのリストの長さをゼロに減らすことですが、現実には、数個の
+    後戻り問題がリリース時にたびたび残ってしまいます。
+
 Andrew Morton が Linux-kernel メーリングリストにカーネルリリースについ
 て書いたことをここで言っておくことは価値があります-
   「カーネルがいつリリースされるかは誰も知りません。なぜなら、これは現
@@ -303,18 +305,20 @@ Andrew Morton が Linux-kernel メーリングリストにカーネルリリー
 2.6.x.y -stable カーネルツリー
 ---------------------------
 
-バージョンに4つ目の数字がついたカーネルは -stable カーネルです。これに
\81¯ã\80\812.6.x ã\82«ã\83¼ã\83\8dã\83«ã\81§è¦\8bã\81¤ã\81\8bã\81£ã\81\9fã\82»ã\82­ã\83¥ã\83ªã\83\86ã\82£å\95\8fé¡\8cã\82\84é\87\8d大ã\81ªå¾\8cæ\88»ã\82\8aã\81«å¯¾ã\81\99ã\82\8bæ¯\94
-較的小さい重要な修正が含まれます。
+バージョン番号が4つの数字に分かれているカーネルは -stable カーネルです。
\81\93ã\82\8cã\81«ã\81¯ã\80\812.6.x ã\82«ã\83¼ã\83\8dã\83«ã\81§è¦\8bã\81¤ã\81\8bã\81£ã\81\9fã\82»ã\82­ã\83¥ã\83ªã\83\86ã\82£å\95\8fé¡\8cã\82\84é\87\8d大ã\81ªå¾\8cæ\88»ã\82\8aã\81«å¯¾
+する比較的小さい重要な修正が含まれます。
 
 これは、開発/実験的バージョンのテストに協力することに興味が無く、
 最新の安定したカーネルを使いたいユーザに推奨するブランチです。
 
-もし、2.6.x.y カーネルが存在しない場合には、番号が一番大きい 2.6.x
-最新の安定版カーネルです。
+もし、2.6.x.y カーネルが存在しない場合には、番号が一番大きい 2.6.x が
+最新の安定版カーネルです。
 
-2.6.x.y は "stable" チーム <stable@kernel.org> でメンテされており、だ
-いたい隔週でリリースされています。
+2.6.x.y は "stable" チーム <stable@kernel.org> でメンテされており、必
+要に応じてリリースされます。通常のリリース期間は 2週間毎ですが、差し迫っ
+た問題がなければもう少し長くなることもあります。セキュリティ関連の問題
+の場合はこれに対してだいたいの場合、すぐにリリースがされます。
 
 カーネルツリーに入っている、Documentation/stable_kernel_rules.txt ファ
 イルにはどのような種類の変更が -stable ツリーに受け入れ可能か、またリ
@@ -341,7 +345,9 @@ linux-kernel メーリングリストで収集された多数のパッチと同
 メインラインへ入れるように Linus にプッシュします。
 
 メインカーネルツリーに含めるために Linus に送る前に、すべての新しいパッ
-チが -mm ツリーでテストされることが強く推奨されます。
+チが -mm ツリーでテストされることが強く推奨されています。マージウィン
+ドウが開く前に -mm ツリーに現れなかったパッチはメインラインにマージさ
+れることは困難になります。
 
 これらのカーネルは安定して動作すべきシステムとして使うのには適切ではあ
 りませんし、カーネルブランチの中でももっとも動作にリスクが高いものです。
@@ -395,13 +401,15 @@ linux-kernel メーリングリストで収集された多数のパッチと同
     - pcmcia, Dominik Brodowski <linux@dominikbrodowski.net>
        git.kernel.org:/pub/scm/linux/kernel/git/brodo/pcmcia-2.6.git
 
-    - SCSI, James Bottomley <James.Bottomley@SteelEye.com>
+    - SCSI, James Bottomley <James.Bottomley@hansenpartnership.com>
        git.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6.git
 
+    - x86, Ingo Molnar <mingo@elte.hu>
+       git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86.git
+
   quilt ツリー-
-    - USB, PCI ドライバコアと I2C, Greg Kroah-Hartman <gregkh@suse.de>
+    - USB, ドライバコアと I2C, Greg Kroah-Hartman <gregkh@suse.de>
        kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/
-    - x86-64 と i386 の仲間 Andi Kleen <ak@suse.de>
 
   その他のカーネルツリーは http://git.kernel.org/ と MAINTAINERS ファ
   イルに一覧表があります。
@@ -412,13 +420,32 @@ linux-kernel メーリングリストで収集された多数のパッチと同
 bugzilla.kernel.org は Linux カーネル開発者がカーネルのバグを追跡する
 場所です。ユーザは見つけたバグの全てをこのツールで報告すべきです。
 どう kernel bugzilla を使うかの詳細は、以下を参照してください-
-       http://test.kernel.org/bugzilla/faq.html
-
+       http://bugzilla.kernel.org/page.cgi?id=faq.html
 メインカーネルソースディレクトリにあるファイル REPORTING-BUGS はカーネ
 ルバグらしいものについてどうレポートするかの良いテンプレートであり、問
 題の追跡を助けるためにカーネル開発者にとってどんな情報が必要なのかの詳
 細が書かれています。
 
+バグレポートの管理
+-------------------
+
+あなたのハッキングのスキルを訓練する最高の方法のひとつに、他人がレポー
+トしたバグを修正することがあります。あなたがカーネルをより安定化させる
+こに寄与するということだけでなく、あなたは 現実の問題を修正することを
+学び、自分のスキルも強化でき、また他の開発者があなたの存在に気がつき
+ます。バグを修正することは、多くの開発者の中から自分が功績をあげる最善
+の道です、なぜなら多くの人は他人のバグの修正に時間を浪費することを好ま
+ないからです。
+
+すでにレポートされたバグのために仕事をするためには、
+http://bugzilla.kernel.org に行ってください。もし今後のバグレポートに
+ついてアドバイスを受けたいのであれば、bugme-new メーリングリスト(新し
+いバグレポートだけがここにメールされる) または bugme-janitor メーリン
+グリスト(bugzilla の変更毎にここにメールされる)を購読できます。
+
+       http://lists.linux-foundation.org/mailman/listinfo/bugme-new
+       http://lists.linux-foundation.org/mailman/listinfo/bugme-janitors
+
 メーリングリスト
 -------------
 
diff --git a/Documentation/ja_JP/SubmitChecklist b/Documentation/ja_JP/SubmitChecklist
new file mode 100644 (file)
index 0000000..6c42e07
--- /dev/null
@@ -0,0 +1,111 @@
+NOTE:
+This is a version of Documentation/SubmitChecklist into Japanese.
+This document is maintained by Takenori Nagano <t-nagano@ah.jp.nec.com>
+and the JF Project team <http://www.linux.or.jp/JF/>.
+If you find any difference between this document and the original file
+or a problem with the translation,
+please contact the maintainer of this file or JF project.
+
+Please also note that the purpose of this file is to be easier to read
+for non English (read: Japanese) speakers and is not intended as a
+fork. So if you have any comments or updates of this file, please try
+to update the original English file first.
+
+Last Updated: 2008/07/14
+==================================
+これは、
+linux-2.6.26/Documentation/SubmitChecklist の和訳です。
+
+翻訳団体: JF プロジェクト < http://www.linux.or.jp/JF/ >
+翻訳日: 2008/07/14
+翻訳者: Takenori Nagano <t-nagano at ah dot jp dot nec dot com>
+校正者: Masanori Kobayashi さん <zap03216 at nifty dot ne dot jp>
+==================================
+
+
+Linux カーネルパッチ投稿者向けチェックリスト
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+本書では、パッチをより素早く取り込んでもらいたい開発者が実践すべき基本的な事柄
+をいくつか紹介します。ここにある全ての事柄は、Documentation/SubmittingPatches
+などのLinuxカーネルパッチ投稿に際しての心得を補足するものです。
+
+ 1: 妥当なCONFIGオプションや変更されたCONFIGオプション、つまり =y, =m, =n
+    全てで正しくビルドできることを確認してください。その際、gcc及びリンカが
+    warningやerrorを出していないことも確認してください。
+
+ 2: allnoconfig, allmodconfig オプションを用いて正しくビルドできることを
+    確認してください。
+
+ 3: 手許のクロスコンパイルツールやOSDLのPLMのようなものを用いて、複数の
+    アーキテクチャにおいても正しくビルドできることを確認してください。
+
+ 4: 64bit長の'unsigned long'を使用しているppc64は、クロスコンパイルでの
+    チェックに適当なアーキテクチャです。
+
+ 5: カーネルコーディングスタイルに準拠しているかどうか確認してください(!)
+
+ 6: CONFIGオプションの追加・変更をした場合には、CONFIGメニューが壊れていない
+    ことを確認してください。
+
+ 7: 新しくKconfigのオプションを追加する際には、必ずそのhelpも記述してください。
+
+ 8: 適切なKconfigの依存関係を考えながら慎重にチェックしてください。
+    ただし、この作業はマシンを使ったテストできちんと行うのがとても困難です。
+    うまくやるには、自分の頭で考えることです。
+
+ 9: sparseを利用してちゃんとしたコードチェックをしてください。
+
+10: 'make checkstack' と 'make namespacecheck' を利用し、問題が発見されたら
+    修正してください。'make checkstack' は明示的に問題を示しませんが、どれか
+    1つの関数が512バイトより大きいスタックを使っていれば、修正すべき候補と
+    なります。
+
+11: グローバルなkernel API を説明する kernel-doc をソースの中に含めてください。
+    ( staticな関数においては必須ではありませんが、含めてもらっても結構です )
+    そして、'make htmldocs' もしくは 'make mandocs' を利用して追記した
+    ドキュメントのチェックを行い、問題が見つかった場合には修正を行ってください。
+
+12: CONFIG_PREEMPT, CONFIG_DEBUG_PREEMPT, CONFIG_DEBUG_SLAB,
+    CONFIG_DEBUG_PAGEALLOC, CONFIG_DEBUG_MUTEXES, CONFIG_DEBUG_SPINLOCK,
+    CONFIG_DEBUG_SPINLOCK_SLEEP これら全てを同時に有効にして動作確認を
+    行ってください。
+
+13: CONFIG_SMP, CONFIG_PREEMPT を有効にした場合と無効にした場合の両方で
+    ビルドした上、動作確認を行ってください。
+
+14: もしパッチがディスクのI/O性能などに影響を与えるようであれば、
+    'CONFIG_LBD'オプションを有効にした場合と無効にした場合の両方で
+    テストを実施してみてください。
+
+15: lockdepの機能を全て有効にした上で、全てのコードパスを評価してください。
+
+16: /proc に新しいエントリを追加した場合には、Documentation/ 配下に
+    必ずドキュメントを追加してください。
+
+17: 新しいブートパラメータを追加した場合には、
+    必ずDocumentation/kernel-parameters.txt に説明を追加してください。
+
+18: 新しくmoduleにパラメータを追加した場合には、MODULE_PARM_DESC()を
+    利用して必ずその説明を記述してください。
+
+19: 新しいuserspaceインタフェースを作成した場合には、Documentation/ABI/ に
+    Documentation/ABI/README を参考にして必ずドキュメントを追加してください。
+
+20: 'make headers_check'を実行して全く問題がないことを確認してください。
+
+21: 少なくともslabアロケーションとpageアロケーションに失敗した場合の
+    挙動について、fault-injectionを利用して確認してください。
+    Documentation/fault-injection/ を参照してください。
+
+    追加したコードがかなりの量であったならば、サブシステム特有の
+    fault-injectionを追加したほうが良いかもしれません。
+
+22: 新たに追加したコードは、`gcc -W'でコンパイルしてください。
+    このオプションは大量の不要なメッセージを出力しますが、
+    "warning: comparison between signed and unsigned" のようなメッセージは、
+    バグを見つけるのに役に立ちます。
+
+23: 投稿したパッチが -mm パッチセットにマージされた後、全ての既存のパッチや
+    VM, VFS およびその他のサブシステムに関する様々な変更と、現時点でも共存
+    できることを確認するテストを行ってください。
index c13cc77..656c2c7 100644 (file)
@@ -293,27 +293,30 @@ void __init printk_all_partitions(void)
 /* iterator */
 static int find_start(struct device *dev, void *data)
 {
-       loff_t k = *(loff_t *)data;
+       loff_t *k = data;
 
        if (dev->type != &disk_type)
                return 0;
-       if (!k--)
+       if (!*k)
                return 1;
+       (*k)--;
        return 0;
 }
 
 static void *part_start(struct seq_file *part, loff_t *pos)
 {
        struct device *dev;
-       loff_t n = *pos;
+       loff_t k = *pos;
 
-       if (!n)
+       if (!k)
                seq_puts(part, "major minor  #blocks  name\n\n");
 
        mutex_lock(&block_class_lock);
-       dev = class_find_device(&block_class, NULL, (void *)pos, find_start);
-       if (dev)
+       dev = class_find_device(&block_class, NULL, &k, find_start);
+       if (dev) {
+               put_device(dev);
                return dev_to_disk(dev);
+       }
        return NULL;
 }
 
@@ -330,8 +333,10 @@ static void *part_next(struct seq_file *part, void *v, loff_t *pos)
        struct device *dev;
        ++*pos;
        dev = class_find_device(&block_class, &gp->dev, NULL, find_next);
-       if (dev)
+       if (dev) {
+               put_device(dev);
                return dev_to_disk(dev);
+       }
        return NULL;
 }
 
@@ -568,11 +573,14 @@ static struct device_type disk_type = {
 static void *diskstats_start(struct seq_file *part, loff_t *pos)
 {
        struct device *dev;
+       loff_t k = *pos;
 
        mutex_lock(&block_class_lock);
-       dev = class_find_device(&block_class, NULL, (void *)pos, find_start);
-       if (dev)
+       dev = class_find_device(&block_class, NULL, &k, find_start);
+       if (dev) {
+               put_device(dev);
                return dev_to_disk(dev);
+       }
        return NULL;
 }
 
@@ -583,8 +591,10 @@ static void *diskstats_next(struct seq_file *part, void *v, loff_t *pos)
 
        ++*pos;
        dev = class_find_device(&block_class, &gp->dev, NULL, find_next);
-       if (dev)
+       if (dev) {
+               put_device(dev);
                return dev_to_disk(dev);
+       }
        return NULL;
 }
 
@@ -712,10 +722,12 @@ dev_t blk_lookup_devt(const char *name, int part)
        mutex_lock(&block_class_lock);
        find.name = name;
        find.part = part;
-       dev = class_find_device(&block_class, NULL, (void *)&find, match_id);
-       if (dev)
+       dev = class_find_device(&block_class, NULL, &find, match_id);
+       if (dev) {
+               put_device(dev);
                devt = MKDEV(MAJOR(dev->devt),
                             MINOR(dev->devt) + part);
+       }
        mutex_unlock(&block_class_lock);
 
        return devt;
index 5667c2f..cc5e28c 100644 (file)
@@ -295,6 +295,12 @@ int class_for_each_device(struct class *class, struct device *start,
 
        if (!class)
                return -EINVAL;
+       if (!class->p) {
+               WARN(1, "%s called for class '%s' before it was initialized",
+                    __func__, class->name);
+               return -EINVAL;
+       }
+
        mutex_lock(&class->p->class_mutex);
        list_for_each_entry(dev, &class->p->class_devices, node) {
                if (start) {
@@ -344,6 +350,11 @@ struct device *class_find_device(struct class *class, struct device *start,
 
        if (!class)
                return NULL;
+       if (!class->p) {
+               WARN(1, "%s called for class '%s' before it was initialized",
+                    __func__, class->name);
+               return NULL;
+       }
 
        mutex_lock(&class->p->class_mutex);
        list_for_each_entry(dev, &class->p->class_devices, node) {
index 068aa1c..d021c98 100644 (file)
@@ -53,7 +53,7 @@ static inline int device_is_not_partition(struct device *dev)
  * it is attached to.  If it is not attached to a bus either, an empty
  * string will be returned.
  */
-const char *dev_driver_string(struct device *dev)
+const char *dev_driver_string(const struct device *dev)
 {
        return dev->driver ? dev->driver->name :
                        (dev->bus ? dev->bus->name :
@@ -541,6 +541,7 @@ void device_initialize(struct device *dev)
        spin_lock_init(&dev->devres_lock);
        INIT_LIST_HEAD(&dev->devres_head);
        device_init_wakeup(dev, 0);
+       device_pm_init(dev);
        set_dev_node(dev, -1);
 }
 
@@ -843,13 +844,19 @@ int device_add(struct device *dev)
 {
        struct device *parent = NULL;
        struct class_interface *class_intf;
-       int error;
+       int error = -EINVAL;
 
        dev = get_device(dev);
-       if (!dev || !strlen(dev->bus_id)) {
-               error = -EINVAL;
-               goto Done;
-       }
+       if (!dev)
+               goto done;
+
+       /* Temporarily support init_name if it is set.
+        * It will override bus_id for now */
+       if (dev->init_name)
+               dev_set_name(dev, "%s", dev->init_name);
+
+       if (!strlen(dev->bus_id))
+               goto done;
 
        pr_debug("device: '%s': %s\n", dev->bus_id, __func__);
 
@@ -897,9 +904,10 @@ int device_add(struct device *dev)
        error = bus_add_device(dev);
        if (error)
                goto BusError;
-       error = device_pm_add(dev);
+       error = dpm_sysfs_add(dev);
        if (error)
-               goto PMError;
+               goto DPMError;
+       device_pm_add(dev);
        kobject_uevent(&dev->kobj, KOBJ_ADD);
        bus_attach_device(dev);
        if (parent)
@@ -917,10 +925,10 @@ int device_add(struct device *dev)
                                class_intf->add_dev(dev, class_intf);
                mutex_unlock(&dev->class->p->class_mutex);
        }
- Done:
+done:
        put_device(dev);
        return error;
- PMError:
DPMError:
        bus_remove_device(dev);
  BusError:
        if (dev->bus)
@@ -944,7 +952,7 @@ int device_add(struct device *dev)
        cleanup_device_parent(dev);
        if (parent)
                put_device(parent);
-       goto Done;
+       goto done;
 }
 
 /**
@@ -1007,6 +1015,7 @@ void device_del(struct device *dev)
        struct class_interface *class_intf;
 
        device_pm_remove(dev);
+       dpm_sysfs_remove(dev);
        if (parent)
                klist_del(&dev->knode_parent);
        if (MAJOR(dev->devt)) {
index 2ef5acf..1e2bda7 100644 (file)
@@ -16,9 +16,6 @@
 #include <linux/string.h>
 #include "base.h"
 
-#define to_dev(node) container_of(node, struct device, driver_list)
-
-
 static struct device *next_device(struct klist_iter *i)
 {
        struct klist_node *n = klist_next(i);
index 3250c52..273a944 100644 (file)
@@ -67,20 +67,16 @@ void device_pm_unlock(void)
  *     device_pm_add - add a device to the list of active devices
  *     @dev:   Device to be added to the list
  */
-int device_pm_add(struct device *dev)
+void device_pm_add(struct device *dev)
 {
-       int error;
-
        pr_debug("PM: Adding info for %s:%s\n",
                 dev->bus ? dev->bus->name : "No Bus",
                 kobject_name(&dev->kobj));
        mutex_lock(&dpm_list_mtx);
        if (dev->parent) {
-               if (dev->parent->power.status >= DPM_SUSPENDING) {
-                       dev_warn(dev, "parent %s is sleeping, will not add\n",
+               if (dev->parent->power.status >= DPM_SUSPENDING)
+                       dev_warn(dev, "parent %s should not be sleeping\n",
                                dev->parent->bus_id);
-                       WARN_ON(true);
-               }
        } else if (transition_started) {
                /*
                 * We refuse to register parentless devices while a PM
@@ -89,13 +85,9 @@ int device_pm_add(struct device *dev)
                 */
                WARN_ON(true);
        }
-       error = dpm_sysfs_add(dev);
-       if (!error) {
-               dev->power.status = DPM_ON;
-               list_add_tail(&dev->power.entry, &dpm_list);
-       }
+
+       list_add_tail(&dev->power.entry, &dpm_list);
        mutex_unlock(&dpm_list_mtx);
-       return error;
 }
 
 /**
@@ -110,7 +102,6 @@ void device_pm_remove(struct device *dev)
                 dev->bus ? dev->bus->name : "No Bus",
                 kobject_name(&dev->kobj));
        mutex_lock(&dpm_list_mtx);
-       dpm_sysfs_remove(dev);
        list_del_init(&dev->power.entry);
        mutex_unlock(&dpm_list_mtx);
 }
index a3252c0..41f51fa 100644 (file)
@@ -1,3 +1,8 @@
+static inline void device_pm_init(struct device *dev)
+{
+       dev->power.status = DPM_ON;
+}
+
 #ifdef CONFIG_PM_SLEEP
 
 /*
@@ -11,12 +16,12 @@ static inline struct device *to_device(struct list_head *entry)
        return container_of(entry, struct device, power.entry);
 }
 
-extern int device_pm_add(struct device *);
+extern void device_pm_add(struct device *);
 extern void device_pm_remove(struct device *);
 
 #else /* CONFIG_PM_SLEEP */
 
-static inline int device_pm_add(struct device *dev) { return 0; }
+static inline void device_pm_add(struct device *dev) {}
 static inline void device_pm_remove(struct device *dev) {}
 
 #endif
index 2e9079d..4190be6 100644 (file)
@@ -33,6 +33,19 @@ config UIO_PDRV
 
          If you don't know what to do here, say N.
 
+config UIO_PDRV_GENIRQ
+       tristate "Userspace I/O platform driver with generic IRQ handling"
+       help
+         Platform driver for Userspace I/O devices, including generic
+         interrupt handling code. Shared interrupts are not supported.
+
+         This kernel driver requires that the matching userspace driver
+         handles interrupts in a special way. Userspace is responsible
+         for acknowledging the hardware device if needed, and re-enabling
+         interrupts in the interrupt controller using the write() syscall.
+
+         If you don't know what to do here, say N.
+
 config UIO_SMX
        tristate "SMX cryptengine UIO interface"
        default n
index e00ce0d..8667bbd 100644 (file)
@@ -1,4 +1,5 @@
 obj-$(CONFIG_UIO)      += uio.o
 obj-$(CONFIG_UIO_CIF)  += uio_cif.o
 obj-$(CONFIG_UIO_PDRV) += uio_pdrv.o
+obj-$(CONFIG_UIO_PDRV_GENIRQ)  += uio_pdrv_genirq.o
 obj-$(CONFIG_UIO_SMX)  += uio_smx.o
index 5d0d2e8..0b4ef39 100644 (file)
@@ -88,6 +88,8 @@ static int uio_pdrv_remove(struct platform_device *pdev)
 
        uio_unregister_device(pdata->uioinfo);
 
+       kfree(pdata);
+
        return 0;
 }
 
@@ -114,5 +116,5 @@ module_exit(uio_pdrv_exit);
 
 MODULE_AUTHOR("Uwe Kleine-Koenig");
 MODULE_DESCRIPTION("Userspace I/O platform driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
 MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c
new file mode 100644 (file)
index 0000000..1f82c83
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * drivers/uio/uio_pdrv_genirq.c
+ *
+ * Userspace I/O platform driver with generic IRQ handling code.
+ *
+ * Copyright (C) 2008 Magnus Damm
+ *
+ * Based on uio_pdrv.c by Uwe Kleine-Koenig,
+ * Copyright (C) 2008 by Digi International Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/uio_driver.h>
+#include <linux/spinlock.h>
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/stringify.h>
+
+#define DRIVER_NAME "uio_pdrv_genirq"
+
+struct uio_pdrv_genirq_platdata {
+       struct uio_info *uioinfo;
+       spinlock_t lock;
+       unsigned long flags;
+};
+
+static irqreturn_t uio_pdrv_genirq_handler(int irq, struct uio_info *dev_info)
+{
+       struct uio_pdrv_genirq_platdata *priv = dev_info->priv;
+
+       /* Just disable the interrupt in the interrupt controller, and
+        * remember the state so we can allow user space to enable it later.
+        */
+
+       if (!test_and_set_bit(0, &priv->flags))
+               disable_irq_nosync(irq);
+
+       return IRQ_HANDLED;
+}
+
+static int uio_pdrv_genirq_irqcontrol(struct uio_info *dev_info, s32 irq_on)
+{
+       struct uio_pdrv_genirq_platdata *priv = dev_info->priv;
+       unsigned long flags;
+
+       /* Allow user space to enable and disable the interrupt
+        * in the interrupt controller, but keep track of the
+        * state to prevent per-irq depth damage.
+        *
+        * Serialize this operation to support multiple tasks.
+        */
+
+       spin_lock_irqsave(&priv->lock, flags);
+       if (irq_on) {
+               if (test_and_clear_bit(0, &priv->flags))
+                       enable_irq(dev_info->irq);
+       } else {
+               if (!test_and_set_bit(0, &priv->flags))
+                       disable_irq(dev_info->irq);
+       }
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return 0;
+}
+
+static int uio_pdrv_genirq_probe(struct platform_device *pdev)
+{
+       struct uio_info *uioinfo = pdev->dev.platform_data;
+       struct uio_pdrv_genirq_platdata *priv;
+       struct uio_mem *uiomem;
+       int ret = -EINVAL;
+       int i;
+
+       if (!uioinfo || !uioinfo->name || !uioinfo->version) {
+               dev_err(&pdev->dev, "missing platform_data\n");
+               goto bad0;
+       }
+
+       if (uioinfo->handler || uioinfo->irqcontrol || uioinfo->irq_flags) {
+               dev_err(&pdev->dev, "interrupt configuration error\n");
+               goto bad0;
+       }
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv) {
+               ret = -ENOMEM;
+               dev_err(&pdev->dev, "unable to kmalloc\n");
+               goto bad0;
+       }
+
+       priv->uioinfo = uioinfo;
+       spin_lock_init(&priv->lock);
+       priv->flags = 0; /* interrupt is enabled to begin with */
+
+       uiomem = &uioinfo->mem[0];
+
+       for (i = 0; i < pdev->num_resources; ++i) {
+               struct resource *r = &pdev->resource[i];
+
+               if (r->flags != IORESOURCE_MEM)
+                       continue;
+
+               if (uiomem >= &uioinfo->mem[MAX_UIO_MAPS]) {
+                       dev_warn(&pdev->dev, "device has more than "
+                                       __stringify(MAX_UIO_MAPS)
+                                       " I/O memory resources.\n");
+                       break;
+               }
+
+               uiomem->memtype = UIO_MEM_PHYS;
+               uiomem->addr = r->start;
+               uiomem->size = r->end - r->start + 1;
+               ++uiomem;
+       }
+
+       while (uiomem < &uioinfo->mem[MAX_UIO_MAPS]) {
+               uiomem->size = 0;
+               ++uiomem;
+       }
+
+       /* This driver requires no hardware specific kernel code to handle
+        * interrupts. Instead, the interrupt handler simply disables the
+        * interrupt in the interrupt controller. User space is responsible
+        * for performing hardware specific acknowledge and re-enabling of
+        * the interrupt in the interrupt controller.
+        *
+        * Interrupt sharing is not supported.
+        */
+
+       uioinfo->irq_flags = IRQF_DISABLED;
+       uioinfo->handler = uio_pdrv_genirq_handler;
+       uioinfo->irqcontrol = uio_pdrv_genirq_irqcontrol;
+       uioinfo->priv = priv;
+
+       ret = uio_register_device(&pdev->dev, priv->uioinfo);
+       if (ret) {
+               dev_err(&pdev->dev, "unable to register uio device\n");
+               goto bad1;
+       }
+
+       platform_set_drvdata(pdev, priv);
+       return 0;
+ bad1:
+       kfree(priv);
+ bad0:
+       return ret;
+}
+
+static int uio_pdrv_genirq_remove(struct platform_device *pdev)
+{
+       struct uio_pdrv_genirq_platdata *priv = platform_get_drvdata(pdev);
+
+       uio_unregister_device(priv->uioinfo);
+       kfree(priv);
+       return 0;
+}
+
+static struct platform_driver uio_pdrv_genirq = {
+       .probe = uio_pdrv_genirq_probe,
+       .remove = uio_pdrv_genirq_remove,
+       .driver = {
+               .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init uio_pdrv_genirq_init(void)
+{
+       return platform_driver_register(&uio_pdrv_genirq);
+}
+
+static void __exit uio_pdrv_genirq_exit(void)
+{
+       platform_driver_unregister(&uio_pdrv_genirq);
+}
+
+module_init(uio_pdrv_genirq_init);
+module_exit(uio_pdrv_genirq_exit);
+
+MODULE_AUTHOR("Magnus Damm");
+MODULE_DESCRIPTION("Userspace I/O platform driver with generic IRQ handling");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
index d24a47f..4d8372d 100644 (file)
@@ -358,6 +358,7 @@ struct device {
 
        struct kobject kobj;
        char    bus_id[BUS_ID_SIZE];    /* position on parent bus */
+       const char              *init_name; /* initial name of the device */
        struct device_type      *type;
        unsigned                uevent_suppress:1;
 
@@ -406,7 +407,7 @@ struct device {
 /* Get the wakeup routines, which depend on struct device */
 #include <linux/pm_wakeup.h>
 
-static inline const char *dev_name(struct device *dev)
+static inline const char *dev_name(const struct device *dev)
 {
        /* will be changed into kobject_name(&dev->kobj) in the near future */
        return dev->bus_id;
@@ -518,7 +519,7 @@ extern void device_shutdown(void);
 extern void sysdev_shutdown(void);
 
 /* debugging and troubleshooting/diagnostic helpers. */
-extern const char *dev_driver_string(struct device *dev);
+extern const char *dev_driver_string(const struct device *dev);
 #define dev_printk(level, dev, format, arg...) \
        printk(level "%s %s: " format , dev_driver_string(dev) , \
               dev_name(dev) , ## arg)
index bd732ff..fbf0ae2 100644 (file)
@@ -223,8 +223,7 @@ static int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,
                return -ENOMEM;
 
        /* ewww... some of these buggers have '/' in the name ... */
-       s = strchr(kobj->name, '/');
-       if (s)
+       while ((s = strchr(kobj->name, '/')))
                s[0] = '!';
 
        kfree(old_name);
index 4fa1f3a..4c9890e 100644 (file)
@@ -344,14 +344,20 @@ static void do_pnp_device_entry(void *symval, unsigned long size,
                                struct module *mod)
 {
        const unsigned long id_size = sizeof(struct pnp_device_id);
-       const struct pnp_device_id *id = symval;
+       const unsigned int count = (size / id_size)-1;
+       const struct pnp_device_id *devs = symval;
+       unsigned int i;
 
        device_id_check(mod->name, "pnp", size, id_size, symval);
 
-       buf_printf(&mod->dev_table_buf,
-                  "MODULE_ALIAS(\"pnp:d%s*\");\n", id->id);
-       buf_printf(&mod->dev_table_buf,
-                  "MODULE_ALIAS(\"acpi*:%s:*\");\n", id->id);
+       for (i = 0; i < count; i++) {
+               const char *id = (char *)devs[i].id;
+
+               buf_printf(&mod->dev_table_buf,
+                          "MODULE_ALIAS(\"pnp:d%s*\");\n", id);
+               buf_printf(&mod->dev_table_buf,
+                          "MODULE_ALIAS(\"acpi*:%s:*\");\n", id);
+       }
 }
 
 /* looks like: "pnp:dD" for every device of the card */