Driver

オイラーの回りでは、すこぶるWindows10の評判が悪い。一例として、春の大型アップデートが実行された後、設定が変わってしまったとか、ネットが遅くなったというもの。ぼやく事しきり。

そんな人へは、(無責任な忠告として)Windows10なんか潰してしまって、Ubuntuでも入れてしまったらと、煽っている。あれなら、アップデートも自分の意志で取捨選択出来るよと。

そんな口車に乗せられて、LetNoteだかのパソコンをUbuntuにしてしまった人がいる。彼曰く、インストールは簡単だったよ。アップデートに失敗しても、数日待ってからやり直せば、ちゃんとアップデートが成功するよと。その技術にいたく感心されてた。

先日の13日は、月毎にやってくる、はらはらドキドキの日。無事に終わった。で、暫く使っていたら、オイラーの所にも、遅い春がやってきたぞ。これから大型アップデートをしますけど、ご都合はいかがですって。そんなのいらねぇーーって喚いても、いずれやアップデートさせられるはめになる。ならば、さっさとやっとくれ。その間に散歩にでも行って来るから。

無事終わってた。新しい機能が有りますって、紹介文を読まされた。頼んでもいないのに、押し付けするな。プンプン!!!

Windows 10 春アップデート、3大機能の特徴を押さえる こういう事らしい。オイラーには全く関係無し。余計なお世話。

高まるLinuxとの互換性、Windows 10春アップデート こんなのも有るようだけど、そんな紛い物の中途半端はいらないよ。

何か設定が変わっていないか、念入りに動作確認。(って言っても、virtualboxとVMwareとfirefoxが動けばOk。)そんな折、マイクロソフトのお店から押し売りが有った。(売ってはいないんで、無料配布か)日本語エクスペリアンスだか言うのをインストールしたから、どうぞ使ってみて下さいですって。

評判が出てたんで見てたら、否定的なものばかり。いいね じゃなくて 悪いね ばかりですよ。曰く、何に使うかさっぱり分からんってのが多かったな。そうだよな、普通の人は、目的が有ってアプリを入れるんだろう。そういう事が、全く分かっていない、いかれトンカチな連中が、店を切り盛りしてるんだろうね。全く迷惑なこっちゃ。

Sample driver on FreeBSD

前回はQEMU上のOpenBSDで、黄金ルートの旅をした。黄金ルートってのは、インバウンドの方にもお馴染み。東京の下町、富士山、京都、大阪の食い倒れをめぐるやつね。日本の歩き方にも 出ているのだろうな。

カーネルが起動してくるまでってのも、今は亡きユニマガに連載されてた。それがムックになって、Linux編とFreeBSD編で出てた。それに倣って、OpenBSD編も駆け足で走り抜けたわけだ。 急ぎ足過ぎたんで、2度目の旅行は、Audioボードが認識されるまでってのをテーマにした。

けど、ドライバーってどういう構成なの? と、問われるとUumですよ。そんなビキナーを指南してくれる例が有ったはず。前から目を付けていたFreeBSDのそれ。

root@fb:~ # cd /usr/share/examples/drivers/
root@fb:/usr/share/examples/drivers # ls -l
total 44
-r--r--r--  1 root  wheel   1916 Jul 21  2017 README
-r--r--r--  1 root  wheel  27795 Jul 21  2017 make_device_driver.sh
-r--r--r--  1 root  wheel   9658 Jul 21  2017 make_pseudo_driver.sh

READMEの一説。

There are presently two scripts.
One for making a real device driver for ISA devices, and
one for making a device driver for pseudo devices (e.g. /dev/null).
Hopefully they will be joined by similar scripts for creating
skeletons for PCI and EISA devices as well.

本格的なのをいきなりやるよりも、軽めのやつで、雰囲気を掴むのが得策かと。

root@fb:/usr/share/examples/drivers # sh make_pseudo_driver.sh foo
Using /usr/src/sys as the path to the kernel sources!
The following files will be created:
/usr/src/sys/modules/foo
/usr/src/sys/conf/files.FOO
/usr/src/sys/i386/conf/FOO
/usr/src/sys/dev/foo
/usr/src/sys/dev/foo/foo.c
/usr/src/sys/sys/fooio.h
/usr/src/sys/modules/foo
/usr/src/sys/modules/foo/Makefile

fooって名前のドライバーを書くとすると、上記のようなファイルを作るとな。面倒なこったい。FreeBSDは、ドライバーを(kldloadを使って)動的にロード出来るようになってるので、モジュールうんぬんってのも必要なんだな。

Do you want to build the 'foo' module? [Y]y
machine -> /usr/src/sys/i386/include
x86 -> /usr/src/sys/x86/include
Warning: Object directory not changed from original /usr/src/sys/modules/foo
cc -O2 -pipe  -fno-strict-aliasing -Werror -D_KERNEL -DKLD_MODULE -nostdinc   -I. -I/usr/src/sys -fno-common   -MD  -MF.depend.foo.o -MTfoo.o -mno-mmx -mno-sse -msoft-float -ffreestanding -fwrapv -fstack-protector -Wall -Wredundant-decls -Wnested-externs -Wstrict-prototypes  -Wmissing-prototypes -Wpointer-arith -Winline -Wcast-qual  -Wundef -Wno-pointer-sign -D__printf__=__freebsd_kprintf__  -Wmissing-include-dirs -fdiagnostics-show-option  -Wno-unknown-pragmas  -Wno-error-tautological-compare -Wno-error-empty-body  -Wno-error-parentheses-equality -Wno-error-unused-function  -Wno-error-pointer-sign -Wno-error-shift-negative-value -Wno-error-address-of-packed-member  -mno-aes -mno-avx  -std=iso9899:1999 -c /usr/src/sys/modules/foo/../../dev/foo/foo.c -o foo.o
/usr/src/sys/modules/foo/../../dev/foo/foo.c:197:1: error: conflicting types for
      'foommap'
foommap(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot)
^
/usr/src/sys/modules/foo/../../dev/foo/foo.c:55:18: note: previous declaration
      is here
static  d_mmap_t        foommap;
                        ^
1 error generated.
*** Error code 1

Stop.
make: stopped in /usr/src/sys/modules/foo

そしてモジュールの作成に失敗。このサンプルスクリプトは10年も前に作られたものなんで、現在の環境と齟齬をきたしているんだろうね。構わず、先に進んでみる。

Do you want to build the 'FOO' kernel? [Y]y
WARNING: duplicate option `KDB' encountered.
Kernel build directory is ../compile/FOO
Don't forget to do ``make cleandepend && make depend''
machine -> ../../../i386/include
x86 -> ../../../x86/include
cc -c -O -pipe -g -nostdinc -I. -I../../.. -I../../../contrib/libfdt -D_KERNEL -
DHAVE_KERNEL_OPTION_HEADERS -include opt_global.h -MD -MF.depend.genassym.o -MTg
enassym.o -mno-mmx -mno-sse -msoft-float -ffreestanding -fwrapv -fstack-protecto
r -gdwarf-2 -Wall -Wredundant-decls -Wnested-externs -Wstrict-prototypes -Wmissi
ng-prototypes -Wpointer-arith -Winline -Wcast-qual -Wundef -Wno-pointer-sign -D_
_printf__=__freebsd_kprintf__ -Wmissing-include-dirs -fdiagnostics-show-option -
Wno-unknown-pragmas -Wno-error-tautological-compare -Wno-error-empty-body -Wno-e
rror-parentheses-equality -Wno-error-unused-function -Wno-error-pointer-sign -Wn
o-error-shift-negative-value -Wno-error-address-of-packed-member -mno-aes -mno-a
vx -std=iso9899:1999 ../../../i386/i386/genassym.c
NM='nm' NMFLAGS='' sh ../../../kern/genassym.sh genassym.o > assym.s
awk -f ../../../tools/vnode_if.awk ../../../kern/vnode_if.src -p
  :

普通にカーネルを作る工程が進みだした。(ので、慌てて中断した)完成させるのが目的じゃなくて、作法を学ぶのが主目的ですから。

$ cat /sys/i386/conf/FOO
# Configuration file for kernel type: FOO
# $FreeBSD$

files           "/usr/src/sys/conf/files.FOO"

include         GENERIC

ident           FOO

# trust me, you'll need this
options         KDB
options         DDB
device          foo

fooってデバイスが追加されてて、関連ファイルが登録されてる。

$ cat /usr/src/sys/conf/files.FOO
dev/foo/foo.c      optional foo

これが、ドライバーの正体を現しているんだな。

$ grep foo /sys/dev/foo/foo.c
 * foo driver
#include <sys/fooio.h>          /* foo IOCTL definitions */
static  d_open_t        fooopen;
static  d_close_t       fooclose;
static  d_read_t        fooread;
static  d_write_t       foowrite;
static  d_ioctl_t       fooioctl;
static  d_mmap_t        foommap;
static  d_poll_t        foopoll;
static struct cdevsw foo_cdevsw = {
        .d_open =       fooopen,
        .d_close =      fooclose,
        .d_read =       fooread,
        .d_write =      foowrite,
        .d_ioctl =      fooioctl,
        .d_poll =       foopoll,
        .d_mmap =       foommap,
        .d_name =       "foo",
struct foo_softc {
typedef struct foo_softc *sc_p;
fooioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
fooopen(struct cdev *dev, int oflags, int devtype, struct thread *td)
fooclose(struct cdev *dev, int fflag, int devtype, struct thread *td)
fooread(struct cdev *dev, struct uio *uio, int ioflag)
foowrite(struct cdev *dev, struct uio *uio, int ioflag)
foommap(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot)
foopoll(struct cdev *dev, int which, struct thread *td)
foo_drvinit(void *unused)
                        printf("foo%d failed to allocate strorage\n", unit);
                scp->dev = make_dev(&foo_cdevsw, unit,
                        UID_ROOT, GID_KMEM, 0640, "foo%d", unit);
SYSINIT(foodev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE+CDEV_MAJOR,
                foo_drvinit, NULL);

ドライバーの名前が決まると、それが接頭語となって、他の(ドライバー等と)干渉しないようになってるとな。名前重要がここでも出現しました。

そして、ドライバーなら必ず備え付けられるべき関数も、定義されてる。(しなければならない)厳しい作法の概要を俯瞰してみた。それぞれの関数の中身も押してしるべしって所かな。

一番簡単そうなデバイス、/dev/nullも、/sys/dev/null/null.c に登録されてた。

/dev/null for OpenBSD

ざっと見、OpenBSDには例が無いみたい。ならば、一番簡単そうな/dev/nullを見ればいいじゃん。

ob$ ls /dev/null
/dev/null
ob$ cd /sys/dev
ob$ ls null*
ls: null*: No such file or directory

あれま? /dev/null有れど、ソースが無い。パッキング漏れしてるのかな? 困った時のman頼み。大した情報は得られず。こうなったら、家宅捜索だ。

ob$ cd /sys
ob$ find . -name '*null*'
./lib/libsa/nullfs.c
./sys/_null.h

ライブラリィーの中に隠れていました。実体は、Null filesystem でしたよ。何でそれが、デバイスに成るの?

       These devices are typically created by:

              mknod -m 666 /dev/null c 1 3
              mknod -m 666 /dev/zero c 1 5
              chown root:root /dev/null /dev/zero

しょうがないので、藁にすがってLinuxでmanしたら、珍しくヒントが出て来た。

再びOpenBSDに戻ってman mknodしたよ。そこから辿って行くと、/dev/MAKEDEVを見ろと指示があった。インストールの最後の方で、デバイスを作ってますって出て来るあれだな。

ob$ less /dev/MAKEDEV
     :
std)
        M console       c 0 0 600
        M tty           c 1 0
        M mem           c 2 0 640 kmem
        M kmem          c 2 1 640 kmem
        M null          c 2 2
        M zero          c 2 12
        M stdin         c 22 0
        M stdout        c 22 1
        M stderr        c 22 2
        M ksyms         c 50 0 640 kmem
        M klog          c 7 0 600
        M xf86          c 2 4 600

これが、スタンダードなデバイス。みんなキャラクターデバイスなのね。

と言う事で、ドライバーとしては、参考にならなかった。真面目にググル先生に聞いてみる。

search driver info for OpenBSD

OpenBSD device driver development

Driver Architecture and Implementation in OpenBSD

OpenBSD Kernel Internals

OpenBSD Journal

BSD Magazines FreeBSDが主体

OpenBSD - FuguItaGuide

そして、久しぶりにOpenBSDにちからを入れておられる方に出会ったぞ。

OpenBSD syuu1228's blog

こちらの方へは、再訪になるかな。

radio

カーネルのconfファイルを見ていると、気になるデバイスが出て来る。radioですって。 まさかアマチュア無線用のラジオでは無いと思うんだけど、一応調べてみる。デバイスなんで、 マニュアルのセクション4にあるはず。

CHIPSETS
     The TEA5757; TEA5759 is a 44-pin integrated AM/FM stereo radio circuit.
     The radio part is based on the TEA5712.  The TEA5757 is used in FM-
     standards in which the local oscillator frequency is above the radio
     frequency (e.g. European and American standards).  The TEA5759 is the
     version in which the oscillator frequency is below the radio frequency
     (e.g. Japanese standards).  To conform with the Japanese standards, it is
     necessary to set the flags' least significant bit to 1.  The TEA5757;
     TEA5759 has a 25-bit read-write shift register.  The TEA5757 chips are
     used in fms(4) cards.

カーラジオにでも搭載されるチップなんですかね。受信周波数より高い局発を必要としてる5757って石と、我らがガラパゴス諸島用の5759って石の2種類が有るとな。

チップの名前が分かれば、検索も容易。テキサスインスツルメンツやフィリップスなんかで、石を製造してるのね。

フィリップスの1999年製のデータシートを落としてきたけど、まだ現役で製造されてるのかしらん。2.5Vから12.5Vの範囲で動作しますって、携帯ラジオに搭載される事を願っているんだな。

radio(4) だけじゃなくて radio(9) もある。セクション9はカーネル側の文書だから、合わせて見ておくといいかも。

     struct radio_hw_if {
             int     (*open)(void *, int, int, struct proc *);
             int     (*close)(void *, int, int, struct proc *);
             int     (*get_info)(void *, struct radio_info *);
             int     (*set_info)(void *, struct radio_info *);
             int     (*search)(void *, int);
     };

     The high level radio driver attaches to the low level driver when the
     latter calls radio_attach_mi.  This call should be

     void
     radio_attach_mi(struct radio_hw_if *rhwp, void *hdlp, struct device * dev)

     The radio_hw_if struct is as shown above.  The hdlp argument is a handle
     to some low level data structure.  It is sent as the first argument to
     all the functions in radio_hw_if when the high level driver calls them.
     dev is the device struct for the hardware device.

/usr/share/man/man9 とかで、他にどんなのが有るか見ておくと吉。前にやったaudioなんてのも有ったぞ。

ob$ wc /sys/dev/radio*
     202     700    5043 /sys/dev/radio.c
      52     305    2018 /sys/dev/radio_if.h
      40     275    1790 /sys/dev/radiovar.h
     294    1280    8851 total

lowレベルのやつは、これしかない。

ob$ egrep '^radio[a-z].*\(' radio.c
radioprobe(struct device *parent, void *match, void *aux)
radioattach(struct device *parent, struct device *self, void *aux)
radioopen(dev_t dev, int flags, int fmt, struct proc *p)
radioclose(dev_t dev, int flags, int fmt, struct proc *p)
radioioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
radioprint(void *aux, const char *pnp)
radiodetach(struct device *self, int flags)
radioactivate(struct device *self, int act)

定義されてた関数群。肝は、radioctl内にあるやつだな。

        switch (cmd) {
        case RIOCGINFO:
                if (sc->hw_if->get_info)
                        error = (sc->hw_if->get_info)(sc->hw_hdl,
                                        (struct radio_info *)data);
                break;
          :

カーネル側と言うか、Top halfからの依頼を、bottom halfのここで受け止めるとな。呼び出される関数はダイナミックに決められているとな。(sc->hw_if構造体の中のメンバー、get_info)

tag jump

前回の目的を持った旅行で、長い呼び出しの履歴が出てきた。その場でフレームを上下して、 ソースを見てもいいんだけど、何となく落ち着かない。だって、gdbでのライブ・セッションなんだもの。

見るべきポイントを押さえた後は、ゆっくりソースを眺めたい。で、タグジャンプですよ。オイラーは、emacs用のTAGSが欲しいんだなあ。

pkg_add ectags をやるんだ。 すると、ectagsが入って、ちゃんとemacs用のTAGSを作れるようになる。後は、 tag jump に倣って、TAGSを作っておけばおk。

起点が、/sys/arch/i386ってのが、新鮮。これもそれも、共通部分が有って、その差分が、/sys/arch/machineという所に置かれているから。綺麗に整理されてて気持ち良い。Linuxのそれは 見た事ないけど(見る気もしないけど)、きっと混沌の館なんだろうな。

カーネル側は上記で十分なんだけど、 OpenBSD kernel hack memo (Boot) で紹介されてる、kernelに行きつく過程も、タグジャンプしたい。

生憎な事に、そこまで親切にはMakefileが出来ていないので、下記で怪しげなTAGSを生成してあげる事にした。

ob$ ectags -e -R /sys/lib/libsa/ /sys/stand/ /sys/arch/i386/stand/

何が怪しげかと言うと、/sys/lib/libsa/loadfile.cの中にある関数、elf32_exec (若しくは、elf64_exec)にジャンプ出来ないの。

ob$ find . | xargs grep elf32_exec
./lib/libsa/loadfile.c: * Both defined, so elf32_exec() and elf64_exec() need to be separately
./lib/libsa/loadfile.c:int elf32_exec(int, Elf32_Ehdr *, u_long *, int);
./lib/libsa/loadfile.c:         rval = elf32_exec(fd, &hdr.elf32, marks, flags);

おーい、お前は何処に隠れているんだよう?

雰囲気的には、lib/libsa/loadfile_elf.c の

int
ELFNAME(exec)(int fd, Elf_Ehdr *elf, u_long *marks, int flags)
{
        Elf_Shdr *shp;
        Elf_Phdr *phdr;
        Elf_Off off;
          :

が、相当してると思うんだけど、からくりが理解出来ないぞ。 それから、同じ場所にある、loadfile.hで定義されてる、marksの配列の意味も意味深!!

ああ、気が付いた。C語界の習慣では、大文字はマクロ。

sys/exec_elf.h:#define ELFNAME(x)     CONCAT(elf,CONCAT(ELFSIZE,CONCAT(_,x)))

こんなのが見つかった。マクロの引数がexecって文字で、そこにごちゃごちゃとappendしていって、関数名を組み立ててる。

emacsで日本語入力

ふぐ板の案内に感化されて、日本語入力系について調べてみた。 OpenBSDだと anthy-9100hp2.tgz と emacs-anthy-9100hp3.tgz を入れるだけ。 設定は、これだけ。

;; inputmethod anthy
(load-library "anthy")
(setq default-input-method 'japanese-anthy)

変換の on/off は、 Ctrl+\ 。細かい事は、

Using anthy

emacsでanthyのキーバインド

業界の標準は、どうもこちらみたいだな。

Linux 快適な日本語入力

更に、Windowsでも もずく を使いましょうなんて記事に出会ったり、有名なCTLキーとCAPSの交換が出てたりで、Windowsも段々Linux化してるな。

Windowsで「Google日本語入力」システムを使う

Ctrl2Capツールで[Ctrl]と[CapsLock]キーを入れ替える(Windows編)

で、mozcを使うと、 ぐぐる様に筒抜けにならないか? 大丈夫ですってググル様が言ってるよ。でも、これってX環境が前提だよね。だったらオイラーみたいなのは、そんなの使わなければいいんだから。 Debianなら、下記でおけ。

deb9:~$ sudo apt install anthy-el
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following additional packages will be installed:
  anthy anthy-common kasumi libanthy0
The following NEW packages will be installed:
  anthy anthy-common anthy-el kasumi libanthy0
0 upgraded, 5 newly installed, 0 to remove and 0 not upgraded.
Need to get 2,921 kB of archives.
After this operation, 14.7 MB of additional disk space will be used.

emacs上でしか、日本語入力出来ないけど、そんなの問題ねぇ。シンプルが一番さ。

日本語辞書とemacsの間の橋渡しは、anthy-agentって言うのが行い。emacsとそのエージェントとの通信は盗聴出来ない仕組み、パイプが担っているとか。これで安心。何とかibusとかいう、わけわかめは嫌いさ。