キャラクタデバイスドライバの登録
Rev.1を表示中。最新版はこちら。
キャラクタデバイスを登録する関数に、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にてファイルオペレーションを設定する必要がありそうです。





