2012-12-24 :-)
_ 今日は一日“歌う声優”三昧
12 時から 24 時までひたすら聞いていた。
_ [pseudo device][NetBSD][擬似デバイス]NetBSD 擬似デバイスを写経した
参考
ここ
コード
http://www.jp.netbsd.org/docs/kernel/pseudo/pseudo_dev_skel.h
http://www.jp.netbsd.org/docs/kernel/pseudo/pseudo_dev_skel.c
/usr/src/sys/arch/i386/include に pseudo_dev_skel.h を設置
/usr/src/sys/arch/i386/i386 に pseudo_dev_skel.c を設置
pseudo_dev_skel.c の先頭に struct skeleton_softc を追加するらしいんだが、いまんとこ↓だけで済んでる。
struct skelton_softc { struct device sc_dev; };
カーネルに新しいデバイスを知らせる
/usr/src/sys/arch/i386/conf/majors.i386
device-major skeleton char 140 skeleton
config(1) に新しいデバイスを知らせる
/usr/src/sys/arch/i386/conf/files.i386
file dev/skeleton.c skeleton needs-flag
とあるんだが、dev には設置してないので結局以下のようにする。
defpseudo skeleton file sys/arch/i386/i386/skeleton.c skeleton needs-flag
カーネルコンフィグファイルに新しいデバイスを追加する
/usr/src/sys/arch/i386/conf/MYKERNEL
pseudo-device skeleton
カーネルを再構築してインストール。
cd /usr/src ./build.sh kernel=MYKERNEL cd ../obj/sys/arch/i386/compile/MYKERNEL mv /netbsd /netbsd.old cp netbsd /netbsd shutdown -r now
手順は上記のとおりなんだが、ドキュメントのままだと ./build.sh したときにエラーになった。
: # compile MYKERNEL/skeleton.o /usr/src/obj/tooldir.NetBSD-6.0-i386/bin/i486--netbsdelf-gcc -mno-sse -mno-sse2 -mno-sse3 -ffreestanding -fno-zero-initialized-in-bss -O2 -fstack-protector -Wstack-protector --param ssp-buffer-size=1 -fno-strict-aliasing -std=gnu99 -Werror -Wall -Wno-main -Wno-format-zero-length -Wpointer-arith -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Wswitch -Wshadow -Wcast-qual -Wwrite-strings -Wno-unreachable-code -Wno-pointer-sign -Wno-attributes -Wextra -Wno-unused-parameter -Wold-style-definition -Wno-sign-compare --sysroot=/usr/src/obj/destdir.i386 -Di386 -I. -I/usr/src/sys/../common/include -I/usr/src/sys/arch -I/usr/src/sys -nostdinc -DMAXUSERS=64 -D_KERNEL -D_KERNEL_OPT -std=gnu99 -I/usr/src/sys/lib/libkern/../../../common/lib/libc/quad -I/usr/src/sys/lib/libkern/../../../common/lib/libc/string -I/usr/src/sys/lib/libkern/../../../common/lib/libc/arch/i386/string -I/usr/src/sys/dist/ipf -I/usr/src/sys/external/isc/atheros_hal/dist -I/usr/src/sys/external/isc/atheros_hal/ic -I/usr/src/sys/external/bsd/drm/dist/bsd-core -I/usr/src/sys/external/bsd/drm/dist/shared-core -I/usr/src/sys/../common/include -I/usr/src/sys/external/bsd/acpica/dist/include -c /usr/src/sys/arch/i386/i386/skeleton.c /usr/src/sys/arch/i386/i386/skeleton.c:51:53: error: expected declaration specifiers or '...' before 'caddr_t' cc1: warnings being treated as errors /usr/src/sys/arch/i386/i386/skeleton.c:60:9: error: initialization from incompatible pointer type /usr/src/sys/arch/i386/i386/skeleton.c:66:1: error: missing initializer /usr/src/sys/arch/i386/i386/skeleton.c:66:1: error: (near initialization for 'skeleton_cdevsw.d_flag') /usr/src/sys/arch/i386/i386/skeleton.c:104:45: error: expected declaration specifiers or '...' before 'caddr_t' /usr/src/sys/arch/i386/i386/skeleton.c: In function 'skeletonioctl': /usr/src/sys/arch/i386/i386/skeleton.c:108:61: error: 'data' undeclared (first use in this function) /usr/src/sys/arch/i386/i386/skeleton.c:108:61: note: each undeclared identifier is reported only once for each function it appears in :
ううん?
u_long command か caddr_t data が定義されてないのか?
マニュアル読む。
man driver
const struct cdevsw foo_cdevsw { int (*d_open)(dev_t, int, int, struct lwp *); int (*d_close)(dev_t, int, int, struct lwp *); int (*d_read)(dev_t, struct uio *, int); int (*d_write)(dev_t, struct uio *, int); int (*d_ioctl)(dev_t, u_long, void *, int, struct lwp *); ←←←←これ void (*d_stop)(struct tty *, int); struct tty *(*d_tty)(dev_t); int (*d_poll)(dev_t, int, struct lwp *); paddr_t (*d_mmap)(dev_t, off_t, int); int (*d_kqfilter)(dev_t, struct knote *); int d_flag; };
d_ioctl の 3 番目に注目。void* になってる。
skeletonioctl() の定義を見ると
struct skeleton_params *params = (struct skeleton_params *)data;
などとキャストしてるし、void * でいいか。
再度 ./build.sh
またエラーになった。
: /usr/src/sys/arch/i386/i386/skeleton.c:68:1: error: missing initializer /usr/src/sys/arch/i386/i386/skeleton.c:68:1: error: (near initialization for 'skeleton_cdevsw.d_flag') :
d_flag って?
man driver を眺めても d_flag は名前しか出てこない。
sys/conf.h を眺める。
これか。
/* * Types for d_flag */ #define D_OTHER 0x0000 #define D_TAPE 0x0001 #define D_DISK 0x0002 #define D_TTY 0x0003 #define D_TYPEMASK 0x00ff #define D_MPSAFE 0x0100 #define D_NEGOFFSAFE 0x0200
デバイスのタイプって?
よく分からないから D_OTHER でいいや。
もともとある const struct cdevsw skeleton_cdevsw の定義には最後のメンバー変数 d_flag が足りないのでエラーになっていたようだ。
/usr/src/sys/arch/i386/isa/cmos.c を参考などにして書きなおすとこうなった。
rin@mogu[/usr/src/sys/arch/i386/i386]% diff -u pseudo_dev_skel.c skeleton.c --- pseudo_dev_skel.c 2009-05-22 00:30:08.000000000 +0900 +++ skeleton.c 2012-12-24 20:19:37.000000000 +0900 @@ -35,27 +35,35 @@ #include <sys/ioctl.h> #include <sys/device.h> #include <sys/conf.h> -#include <sys/pseudo_dev_skel.h> +#include <arch/i386/include/skeleton.h> + + +struct skelton_softc { + struct device sc_dev; +}; + + /* Autoconfiguration glue */ void skeletonattach(int num); int skeletonopen(dev_t device, int flags, int fmt, struct lwp *process); int skeletonclose(dev_t device, int flags, int fmt, struct lwp *process); -int skeletonioctl(dev_t device, u_long command, caddr_t data, +int skeletonioctl(dev_t device, u_long command, void* data, int flags, struct lwp *process); /* just define the character device handlers because that is all we need */ const struct cdevsw skeleton_cdevsw = { - skeletonopen, - skeletonclose, - noread, - nowrite, - skeletonioctl, - nostop, - notty, - nopoll, - nommap, - nokqfilter, + .d_open = skeletonopen, + .d_close = skeletonclose, + .d_read = noread, + .d_write = nowrite, + .d_ioctl = skeletonioctl, + .d_stop = nostop, + .d_tty = notty, + .d_poll = nopoll, + .d_mmap = nommap, + .d_kqfilter = nokqfilter, + .d_flag = D_OTHER, }; /* @@ -94,7 +102,7 @@ * Handle the ioctl for the device */ int -skeletonioctl(dev_t device, u_long command, caddr_t data, int flags, +skeletonioctl(dev_t device, u_long command, void* data, int flags, struct lwp *process) { int error;
ユーザーレベルプログラムが新しいデバイスにアクセスすることを許す
mknod /dev/skel c 140 0
/bin/ls -l /dev/skel crw-r--r-- 1 root wheel 140, 0 Dec 24 18:51 /dev/skel
ヘッダーファイル skeleton.h をインストールするために sys/arch/i386/include/Makefile に追加。
rin@mogu[/usr/src/sys/arch/i386/include]% diff -u Makefile.orig Makefile --- Makefile.orig 2012-12-24 20:57:11.000000000 +0900 +++ Makefile 2012-12-24 20:57:31.000000000 +0900 @@ -24,6 +24,7 @@ svr4_machdep.h sysarch.h \ trap.h tss.h types.h \ vm86.h vmparam.h \ - wchar_limits.h + wchar_limits.h \ + skeleton.h
make includes するとインストールされる。
rin@mogu[/usr/src/sys/arch/i386/include]% sudo make includes # install /usr/include/i386/skeleton.h /usr/src/obj/tooldir.NetBSD-6.0-i386/bin/i486--netbsdelf-install -N /usr/src/etc -c -r -c -o root -g wheel -m 444 skeleton.h /usr/include/i386/skeleton.h
sample.c は include だけ変更。
rin@mogu[~/work/OS/NetBSD/device driver]% diff -u sample.c.orig sample.c --- sample.c.orig 2007-06-09 20:33:50.000000000 +0900 +++ sample.c 2012-12-24 21:23:00.000000000 +0900 @@ -33,7 +33,8 @@ #include <stdlib.h> #include <string.h> #include <sys/ioctl.h> -#include <sys/pseudo_dev_skel.h> +#include <i386/skeleton.h> + int main() {
コンパイル。
cc -o sample sample.c
実行
./sample
/var/log/message はこうなる。
Dec 24 20:59:25 mogu /netbsd: Got number of 42 and string of Hello World