キャラクタデバイスドライバの登録
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にてファイルオペレーションを設定する必要がありそうです。