キャラクタデバイスドライバの登録


キャラクタデバイスを登録する関数に、register_chrdev、register_chrdev_regionおよびalloc_chrdev_regionが用意されています。キャラクタデバイスはメジャー番号とベースマイナー番号の組み合わせた数値で識別され、1つのキャラクタデバイスで複数のマイナー番号をサポートしています。

register_chrdevは指定されたメジャー番号に対するドライバーはマイナー番号0から255までをサポートするようなドライバーとして登録し、register_chrdev_regionはサポートする個数分、メジャー番号を上げながら指定されたマイナー番号とで、ドライバーを登録するようです。一度に同じようなドライバーを複数登録する場合便利なようです。alloc_chrdev_regionは空いているメージャー番号を探し出し、指定したマイナー番号で登録するものです。

同じメジャー番号でマイナー番号毎に、それぞれのデバイスを登録することが可能のようみたいですが・・・。ただし、同じメジャー番号で、サポートするマイナー番号が重なるかたちで、デバイスを登録することはできないようです。

これら3つの関数は、仕様に応じた引数で、最終的に__register_chrdev_regionが呼ばれます。chrdevs[]から空いているインデックスを探し出し、それをメジャー番号としています。

最初にmajor=0で呼ばれたときのチェックです。alloc_chrdev_regionのケースです。その後struct char_device_structのメンバーに値をセットして後、マイナー番号エリアが重なっているかどうかのチェックをしています。重なるようだとエラーのようです。
static struct char_device_struct *
__register_chrdev_region(unsigned int major, unsigned int baseminor,
                          int minorct, const char *name)
{
       struct char_device_struct *cd, **cp;
       int ret = 0;
       int i;

       cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL);
       if (cd == NULL)
               return ERR_PTR(-ENOMEM);

       mutex_lock(&chrdevs_lock);

       /* temporary */
       if (major == 0) {
               for (i = ARRAY_SIZE(chrdevs)-1; i > 0; i--) {
                       if (chrdevs[i] == NULL)
                               break;
               }

               if (i == 0) {
                       ret = -EBUSY;
                       goto out;
               }
               major = i;
               ret = major;
       }

       cd->major = major;
       cd->baseminor = baseminor;
       cd->minorct = minorct;
       strncpy(cd->name,name, 64);

       i = major_to_index(major);

       for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
               if ((*cp)->major > major ||
                   ((*cp)->major == major &&
                    (((*cp)->baseminor >= baseminor) ||
                     ((*cp)->baseminor + (*cp)->minorct > baseminor))))
                       break;

       /* Check for overlapping minor ranges.  */
       if (*cp && (*cp)->major == major) {
               int old_min = (*cp)->baseminor;
               int old_max = (*cp)->baseminor + (*cp)->minorct - 1;
               int new_min = baseminor;
               int new_max = baseminor + minorct - 1;

               /* New driver overlaps from the left.  */
               if (new_max >= old_min && new_max <= old_max) {
                       ret = -EBUSY;
                       goto out;
               }

               /* New driver overlaps from the right.  */
               if (new_min <= old_max && new_min >= old_min) {
                       ret = -EBUSY;
                       goto out;
               }
       }

       cd->next = *cp;
       *cp = cd;
       mutex_unlock(&chrdevs_lock);
       return cd;
out:
       mutex_unlock(&chrdevs_lock);
       kfree(cd);
       return ERR_PTR(ret);
}
なお、引数のファイルオペレーション(ドライバの実態)を伴うregister_chrdevでは、これでデバイスドライバが使用可能となります。_regionでの登録は個別にcdev_initにてファイルオペレーションを設定する必要がありそうです。



最終更新 2010/01/25 18:55:44 - north
(2010/01/25 18:21:07 作成)


検索

アクセス数
3585792
最近のコメント
コアダンプファイル - sakaia
list_head構造体 - yocto_no_yomikata
勧告ロックと強制ロック - wataash
LKMからのファイル出力 - 重松 宏昌
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
Adsense
広告情報が設定されていません。