Out of Treeコンパイルは、atmark-distに変更を加えることなく手軽に開発できる方法です。atmark-dist
のビルドシステムを使うため、複雑なMakefile
を書く必要もありません。atmark-dist
のディレクトリ構造を木に見たて、そのディレクトリ外でコンパイルするためにこう呼ばれています。
以下に、仮想の(キャラクタ)デバイスドライバを例に作成方法を説明します。
なお、以下の例では、2.6系のカーネルを使用しています。
Out of Treeコンパイルでは、atmark-dist
に含まれるビルドシステムやライブラリ群を使うため、一度ビルドされているatmark-dist
が必要です。まず、atmark-dist
がターゲットボード用にコンフィギュレーションかつビルドされていることを確認してください。
次に、開発するデバイスドライバ用のディレクトリをatmark-dist
のディレクトリ構造の外に用意します。この中には、Makefile
と必要なCのソースコードやヘッダファイルを配置します。
[PC ~]$
ls
atmark-dist-[version]
[PC ~]$
mkdir message
[PC ~]$
ls
atmark-dist-[version] message
[PC ~]$
ls message
Makefile message.c
message.c
は、以下を使用します。
/**
* Character Device Driver Sample:
* file name: message.c
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/string.h>
#include <asm/uaccess.h>
#include <linux/cdev.h>
#define LICENSE "GPL v2"
#define MSG_LEN (32)
static int driver_major_no = 0;
static char msg[MSG_LEN] = "Hello, everyone.";
static struct cdev char_dev;
module_param_string(msg, msg, MSG_LEN, 0);
static int message_open(struct inode *inode, struct file *filp)
{
pr_debug("message_open\n");
return 0;
}
static int message_read(struct file *filp, char *buff, size_t count, loff_t
*pos)
{
size_t read_size;
if (count < strlen(msg) - *pos)
read_size = count;
else
read_size = strlen(msg) - *pos;
pr_debug("message_read: size = %d\n", read_size);
if (read_size) {
copy_to_user(buff, &msg[*pos], read_size);
*pos += read_size;
}
return read_size;
}
static int message_release(struct inode *inode, struct file *filp)
{
pr_debug("message_release\n");
return 0;
}
static struct file_operations driver_fops = {
.read = message_read,
.open = message_open,
.release = message_release,
};
int init_module(void)
{
int ret;
dev_t dev = MKDEV(driver_major_no, 0);
pr_debug("message: init_module: msg = %s\n", msg);
cdev_init(&char_dev, &driver_fops);
char_dev.owner = THIS_MODULE;
ret = cdev_add(&char_dev, dev, 1);
if (ret < 0) {
pr_debug("message: Major no. cannot be assigned.\n");
return ret;
}
if (driver_major_no == 0) {
driver_major_no = ret;
printk("message: Major no. is assigned to %d.\n", ret);
}
return 0;
}
void cleanup_module(void)
{
pr_debug("message: cleanup_module\n");
cdev_del(&char_dev);
}
MODULE_LICENSE(LICENSE);
Makfile
は、以下を使用します。
MODULES = message.o
ifneq ($(KERNELRELEASE), )
obj-m := $(MODULES)
#CFLAGS_MODULE += -DDEBUG
else
ROOTDIR ?= ../atmark-dist-[version]
ROMFSDIR = $(ROOTDIR)/romfs
include $(ROOTDIR)/.config
include $(ROOTDIR)/config.arch
MAKEARCH = $(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE)
LINUXDIR = $(CONFIG_LINUXDIR)
KERNELRELEASE = ${shell make -sC $(ROOTDIR)/$(LINUXDIR) kernelrelease}
all: modules romfs
modules:
$(MAKEARCH) -C $(ROOTDIR)/$(LINUXDIR) M=${shell pwd} modules
romfs:
make -C $(ROOTDIR) INSTALL_MOD_DIR=kernel/drivers/char \
M=${shell pwd} modules_install
$(ROOTDIR)/user/busybox/examples/depmod.pl -b \
$(ROMFSDIR)/lib/modules/$(KERNELRELEASE) &> /dev/null
clean:
-rm -f *.[oas] *.ko *.mod.c .*.d .*.tmp .*.cmd *.symvers
-rm -rf .tmp_versions
distclean: clean
-rm -f *~
endif
このMakefile
は、他のデバイスドライバを開発するときにもテンプレートとして使用することができます。環境に合わせて変更する点は、以下の2つです。
|
生成されるモジュールファイル名を指定します。
|
|
ROOTDIRには、atmark-dist ディレクトリを指定します。
|
Makefile
とmessage.c
の用意ができたら、message.ko
をビルドします。ビルドにはmake
コマンドでmoduelsターゲットを使用します。ビルドが完了するとモジュールファイルmessage.ko
がディレクトリ内に生成されます。
[PC ~/message]$
make modules
:
[PC ~/message]$
ls
Makefile message.c message.mod.c message.o
Module.symvers message.ko message.mod.o
モジュールファイルをatmark-dist
のromfs
ディレクトリにインストールするために、make
コマンドでromfs
ターゲットを指定します。
[PC ~/message]$
make romfs
:
[PC ~/message]$
ls ../atmark-dist-[version]/romfs/lib/modules/[version]/kernel/drivers
/char
message.ko
make romfs
を実行後、atmark-dist
のディレクトリに移動して、make image
を実行することで、message.ko
モジュールを含んだターゲットボード用のイメージファイルがimage
ディレクトリに生成されます。
[PC ~/message]$
cd ../atmark-dist-[version]
[PC ~/uClinux-dist]$
make image
[PC ~/uClinux-dist]$
ls images
linux.bin linux.bin.gz romfs.img romfs.img.gz
image
ターゲットについては、「image」を参照してください。
作成したデバイスドライバをディストリビューションに含める方法について説明します。デバイスドライバは、linux-2.6.xディレクトリのdriversディレクトリにまとめられています。この下には、デバイスをさらにカテゴリ分けし管理されています。
以下に、先に作成したキャラクタデバイスドライバmessageを例にマージする手順を説明します。
Cのソースコードは、「ソースコードの用意」と同じものを使用します。ソースコード(message.c
)は、atmark-dist/linux-2.6.x/drivers/char
ディレクトリに配置します。
atmark-dist/linux-2.6.x/drivers/char
ディレクトリにあるKconfig
とMakefile
を編集します。具体的な変更箇所は、以下のとおりです。
例11.1 atmark-dist/linux-2.6.x/drivers/char/Kconfig
の変更点
--- Kconfig.orig 2006-06-22 15:13:39.000000000 +0900
+++ Kconfig 2007-10-01 18:38:35.000000000 +0900
@@ -24,6 +24,9 @@
tristate "Armadillo-220/230/240 Tact Switch driver"
depends on ARCH_ARMADILLO2X0
+config MESSAGE
+ tristate "Message support"
+
config VT
bool "Virtual terminal" if EMBEDDED
select INPUT
例11.2 atmark-dist/linux-2.6.x/drivers/char/Makefile
の変更点
--- Makefile.orig 2006-06-14 19:19:35.000000000 +0900
+++ Makefile 2007-10-01 18:22:34.000000000 +0900
@@ -18,6 +18,7 @@
obj-$(CONFIG_ARMADILLO2X0_GPIO) += armadillo2x0_gpio.o
obj-$(CONFIG_ARMADILLO2X0_LED) += armadillo2x0_led.o
obj-$(CONFIG_ARMADILLO2X0_SW) += armadillo2x0_sw.o
+obj-$(CONFIG_MESSAGE) += message.o
obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o consolemap.o \
consolemap_deftbl.o selection.o keyboard.o
make menuconfig
などで追加したドライバが、Character devicesセクションに表示されるか確認します。表示されたmessageドライバを選択し、設定を保存します。
In Treeコンパイルのビルド方法は「ビルド」と同じです。
追加したデバイスドライバの動作を、アプリケーションプログラムを利用して確認します。
動作確認を行うには、事前に、「インストール」または、「ビルド」までを実行している必要があります。
アプリケーションプログラムは、以下のmodule_test.c
を使用します。ビルドの方法については、10章新規アプリケーションの追加方法を参照してください。
/**
* file name: modules_test.c
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#define DEVNAME "/dev/message"
#define BUFSIZE (64)
int main(void)
{
int fd;
int ret;
int i = 0;
char buf[BUFSIZE];
fd = open(DEVNAME, O_RDONLY);
if (fd < 0) {
perror("open");
return -1;
}
memset(buf, 0, BUFSIZE);
do {
ret = read(fd, buf + i, BUFSIZE - 1 - i);
if (ret < 0) {
perror("read");
return -1;
}
i += ret;
} while (ret && i < (BUFSIZE - 1));
close(fd);
printf("msg: %s\n", buf);
return 0;
}
まず、お使いの製品のソフトウェアマニュアルを参照して、作成したイメージファイルを製品に書き込みます。その後、追加したデバイスドライバのモジュールをカーネルに登録し[]、デバイスノードを作成します。
[Target /]#
modprobe message
Using /lib/modules/[version]/kernel/driversmessage: Major no. is assigned to 0.
/char/message.ko
[Target /]#
mknod /dev/message c 0 0
| |
---|
デバイスノードの作成は、書き込み可能なディレクトリで行なう必要があります。例では「/dev」以下に 「message」というデバイスノードを作成しますので、 /devが書き込み可能なディレクトリであることを確認してください。 ルートファイルシステムに romfs を使用している場合は、/devに tmpfsをマウントするか、他の書き込み可能な場所にデバイスノードを作成し、プログラム内の DEVNAMEを作成したデバイスノードに合せて変更してください。 |
アプリケーションプログラムを実行します。以下のように表示されると追加したドライバが動作していることが確認できます。
[Target /]#
module_test
msg: Hello, everyone.
[Target /]#