Pylone Blog - 2008年11月
sysfs 経由でモジュールパラメータにアクセス (2)
Fri, 14 Nov 2008 04:24 GMT, Posted by Seiichi SATO
以前の記事で sysfs からモジュールパラメータにアクセスする簡単な方法を紹介しましたが、今回はパラメータの型を独自に定義する例として Base36 のパラメータを持つ簡単なモジュールを紹介します。
コード
base36param.c:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
static int stored_value = 0;
static int param_set_base36(const char *val, struct kernel_param *kp)
{
if (('0' <= val[0]) && (val[0] <= '9')) {
stored_value = val[0] -'0';
return 0;
}
if (('a' <= val[0]) && (val[0] <= 'z')) {
stored_value = val[0] -'a' +10;
return 0;
}
if (('A' <= val[0]) && (val[0] <= 'Z')) {
stored_value = val[0] -'A' +10;
return 0;
}
return -EINVAL;
}
static int param_get_base36(char *buffer, struct kernel_param *kp)
{
if (stored_value < 0 || 36 < stored_value)
return -EINVAL;
if (stored_value < 10)
buffer[0] = '0' + stored_value;
else
buffer[0] = 'A' + stored_value - 10;
buffer[1] = '\0';
return 2;
}
/* dummy checker */
#define param_check_base36(name, p) __param_check(name, p, void);
static int __init base36param_init(void)
{
printk(KERN_INFO "%s called\n", __func__);
return 0; /* succeeded */
}
static void __exit base36param_cleanup(void)
{
printk(KERN_INFO "%s called\n", __func__);
return;
}
module_init(base36param_init);
module_exit(base36param_cleanup);
module_param(stored_value, base36, 0644);
MODULE_PARM_DESC(stored_value, "can write [0-9A-Za-z], read as [0-9A-Z].");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("MINAMI Hirokazu");
MODULE_DESCRIPTION("sample module which has a custom typed parameter");
Makefile:
KERNEL_SRC = /lib/modules/$(shell uname -r)/build
#CROSS_COMPILE =
#ARCH =
BUILD_DIR := $(shell pwd)
VERBOSE = 0
obj-m := base36param.o
all:
make -C $(KERNEL_SRC) SUBDIRS=$(BUILD_DIR) KBUILD_VERBOSE=$(VERBOSE) modules
clean:
rm -rf *.o *.ko *.mod.c .*.cmd .tmp_versions *~ Module.symvers
ビルド
環境に応じて Makefile の KERNEL_SRC, CROSS_COMPILE, ARCH を修正し、make を実行します。
使い方
値 (Base36) をパラメータに書き込む:
# echo 'h' > /sys/module/base36param/parameters/stored_value
パラメータを読み込む:
# cat /sys/module/base36param/parameters/stored_value H
解説
モジュールパラメータに独自の型を持たせるためには、 module_param を使います。
module_param(stored_value, base36, 0644);
module_param は以下のようなマクロです。
/* Helper functions: type is byte, short, ushort, int, uint, long, ulong, charp, bool or invbool, or XXX if you define param_get_XXX, param_set_XXX and param_check_XXX. */ #define module_param_named(name, value, type, perm) \ param_check_##type(name, &(value)); \ module_param_call(name, param_set_##type, param_get_##type, &value, perm); \ __MODULE_PARM_TYPE(name, #type) #define module_param(name, type, perm) \ module_param_named(name, name, type, perm)
param_set_##type と param_get_##type が肝です。 sysfs 経由でパラメータが読み書きされると、ここで登録される param_set_##type と param_get_##type が呼ばれます。 (module_param_call の説明は省きます)
base36param.c の場合、プリプロセッサによってマクロ展開された param_set_base36 と param_get_base36 が登録されることになります。
マクロのコメントにある通り、 独自の型ではなく int などの場合は あらかじめ用意されているヘルパー関数群が使われるので 自前で用意する必要はありません。
先日公開した 仮想バッテリドライバ はこれの応用です。 ファイルとして読み書きできるので ユーザ空間のプログラムとヘッダを共有する必要がない点は ioctl(2) より使い勝手がよいかもしれません。