OS上でキーボードを動かすまでの話
CPU実験も無事終わり、余興の余興をやりたいと思い、かねてからの目標であったキーボードドライバを作ろうと思った。
twoproc
VHDL書けないのでtwoprocについて周りの優秀な人たちが教えてくれた資料やアドバイスをまとめる。
- 参考資料を読む
- twoprocで書かれたコードを読む
参考資料
twoprocで書かれたコード
キーボードコントローラ
とりあえず何となく分かったので、次に普及品であるintel 8042キーボードコントローラについて調べた。
ここのサイトが詳しい。
KBC/Intel 8042 - OS Project Wiki
こんな感じになるのかな
PS/2プロトコル
ここのサイトにPS/2の仕様が記載されているので、まとめる。
PS/2は6-pin Mini-DINという規格で、Data,Clockの2本のシリアルバスで双方向通信を行う。
キーボード→コントローラの通信
DataとClockはどちらもHighの状態から始まる。デバイスが情報を送ろうとするとき最初にClockがHighであるかチェックし、もしLowなら中断する。すなわちKBCは送信したい命令がなければClock <= 'H'を送り続けていればよい。
通信は0xxxxxxxxp1の11bitであり、もしKBCが中断させたい場合はstop bitが送られるまでに100マイクロ秒以上Clock <= '0'を送ればよい。
Clockの立ち上がりでDataは次のbitへ5マイクロ秒以内に切り替える。Dataの切り替えからClockの下がりまで5~25マイクロ秒以内でなければならない。つまりfalling_edgeかClock = '0'でDataを読み込めば良い訳だけど、立ち上がるまでの時間すなわち周波数が10~16.7kHzを幅があるので、falling_edgeの方がいいっぽい。
中断されたとき用にキーボードは16byteの出力バッファを持っているらしい。
コントローラ→キーボードの通信
最初にPS/2デバイスは常にClock信号を生成している。もしKBCがデータを送りたいとき、以下の手順に従う。
- 100マイクロ秒以上Clock <= '0'を送る。
- Data <= '0'を送る。
- Clock <= 'H'を送り、「Request-to-send」状態にする。(start bitの送信)
- デバイスがClockを'0'にするのを待つ。
- 送りたいデータのbitにDataを設定する。
- デバイスがClockを'1'にするのを待つ。
- デバイスがClockを'0'にするのを待つ。
- 5-7を残りの7ビットとパリティビットに関して繰り返す。
- Data <= 'H'を送る。(STOP)
- デバイスがData<='0'にするのを待つ。
- デバイスがClock<='0'にするのを待つ。
- デバイスがData<='H'、Clock<='H'にするのを待つ。(ACK)
ClockがLowの時にKBCはデータを変更し、ClockがHighの時にデバイスがDataを受信する。最初のKBCによるClock<='0'からデバイスによるClock<='0'までの間隔は15ミリ秒未満である必要があり、パケットの送信は2ミリ秒以内になされる必要がある。これを超過した場合、または応答を必要とするコマンドをKBCが送って20ミリ秒以上経っても応答がない場合KBCはTimeoutフラグを立てる必要がある。ACKをKBCが受け取ってからデータを処理するまではClock <= '0'にしておいた方がよい。中断するにはACK来るまで(11ビット目まで)にClock<='0'を100マイクロ秒以上送りつづける。
と、ここまで書いたが授業が始まったので続きはまたこんどで
VMware Playerでファイル共有ができなくなった話
以下のようなエラーメッセージが出てファイル共有だけが有効にならなかった。
In file included from ./arch/x86/include/asm/percpu.h:44:0, from ./arch/x86/include/asm/preempt.h:5, from include/linux/preempt.h:18, from include/linux/spinlock.h:50, from include/linux/mmzone.h:7, from include/linux/gfp.h:5, from include/linux/mm.h:9, from include/linux/pagemap.h:7, from /tmp/modconfig-Etbo2b/vmhgfs-only/inode.c:29: /tmp/modconfig-Etbo2b/vmhgfs-only/inode.c: In function ‘HgfsPermission’: /tmp/modconfig-Etbo2b/vmhgfs-only/inode.c:1928:31: error: ‘union <anonymous>’ has no member named ‘d_alias’ d_u.d_alias) { ^ include/linux/kernel.h:834:29: note: in definition of macro ‘container_of’ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ ^ include/linux/list.h:698:15: note: in expansion of macro ‘hlist_entry’ ____ptr ? hlist_entry(____ptr, type, member) : NULL; \ ^ include/linux/list.h:708:13: note: in expansion of macro ‘hlist_entry_safe’ for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\ ^ /tmp/modconfig-Etbo2b/vmhgfs-only/inode.c:1920:7: note: in expansion of macro ‘hlist_for_each_entry’ hlist_for_each_entry(dentry, ^ include/linux/kernel.h:834:48: warning: initialization from incompatible pointer type const typeof( ((type *)0)->member ) *__mptr = (ptr); \ ^ include/linux/list.h:687:40: note: in expansion of macro ‘container_of’ #define hlist_entry(ptr, type, member) container_of(ptr,type,member) ^ include/linux/list.h:698:15: note: in expansion of macro ‘hlist_entry’ ____ptr ? hlist_entry(____ptr, type, member) : NULL; \ ^ include/linux/list.h:708:13: note: in expansion of macro ‘hlist_entry_safe’ for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\ ^ /tmp/modconfig-Etbo2b/vmhgfs-only/inode.c:1920:7: note: in expansion of macro ‘hlist_for_each_entry’ hlist_for_each_entry(dentry, ^ In file included from include/linux/compiler-gcc.h:106:0, from include/linux/compiler.h:54, from include/uapi/linux/stddef.h:1, from include/linux/stddef.h:4, from ./include/uapi/linux/posix_types.h:4, from include/uapi/linux/types.h:13, from include/linux/types.h:5, from /tmp/modconfig-Etbo2b/vmhgfs-only/./shared/driver-config.h:71, from /tmp/modconfig-Etbo2b/vmhgfs-only/inode.c:26: include/linux/compiler-gcc4.h:14:34: error: ‘union <anonymous>’ has no member named ‘d_alias’ #define __compiler_offsetof(a,b) __builtin_offsetof(a,b) ^ include/linux/stddef.h:17:31: note: in expansion of macro ‘__compiler_offsetof’ #define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER) ^ include/linux/kernel.h:835:29: note: in expansion of macro ‘offsetof’ (type *)( (char *)__mptr - offsetof(type,member) );}) ^ include/linux/list.h:687:40: note: in expansion of macro ‘container_of’ #define hlist_entry(ptr, type, member) container_of(ptr,type,member) ^ include/linux/list.h:698:15: note: in expansion of macro ‘hlist_entry’ ____ptr ? hlist_entry(____ptr, type, member) : NULL; \ ^ include/linux/list.h:708:13: note: in expansion of macro ‘hlist_entry_safe’ for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\ ^ /tmp/modconfig-Etbo2b/vmhgfs-only/inode.c:1920:7: note: in expansion of macro ‘hlist_for_each_entry’ hlist_for_each_entry(dentry, ^ In file included from include/linux/preempt.h:10:0, from include/linux/spinlock.h:50, from include/linux/mmzone.h:7, from include/linux/gfp.h:5, from include/linux/mm.h:9, from include/linux/pagemap.h:7, from /tmp/modconfig-Etbo2b/vmhgfs-only/inode.c:29: /tmp/modconfig-Etbo2b/vmhgfs-only/inode.c:1928:31: error: ‘union <anonymous>’ has no member named ‘d_alias’ d_u.d_alias) { ^ include/linux/list.h:697:12: note: in definition of macro ‘hlist_entry_safe’ ({ typeof(ptr) ____ptr = (ptr); \ ^ /tmp/modconfig-Etbo2b/vmhgfs-only/inode.c:1920:7: note: in expansion of macro ‘hlist_for_each_entry’ hlist_for_each_entry(dentry, ^ /tmp/modconfig-Etbo2b/vmhgfs-only/inode.c:1928:31: error: ‘union <anonymous>’ has no member named ‘d_alias’ d_u.d_alias) { ^ include/linux/list.h:697:28: note: in definition of macro ‘hlist_entry_safe’ ({ typeof(ptr) ____ptr = (ptr); \ ^ /tmp/modconfig-Etbo2b/vmhgfs-only/inode.c:1920:7: note: in expansion of macro ‘hlist_for_each_entry’ hlist_for_each_entry(dentry, ^ In file included from ./arch/x86/include/asm/percpu.h:44:0, from ./arch/x86/include/asm/preempt.h:5, from include/linux/preempt.h:18, from include/linux/spinlock.h:50, from include/linux/mmzone.h:7, from include/linux/gfp.h:5, from include/linux/mm.h:9, from include/linux/pagemap.h:7, from /tmp/modconfig-Etbo2b/vmhgfs-only/inode.c:29: /tmp/modconfig-Etbo2b/vmhgfs-only/inode.c:1928:31: error: ‘union <anonymous>’ has no member named ‘d_alias’ d_u.d_alias) { ^ include/linux/kernel.h:834:29: note: in definition of macro ‘container_of’ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ ^ include/linux/list.h:698:15: note: in expansion of macro ‘hlist_entry’ ____ptr ? hlist_entry(____ptr, type, member) : NULL; \ ^ include/linux/list.h:710:13: note: in expansion of macro ‘hlist_entry_safe’ pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member)) ^ /tmp/modconfig-Etbo2b/vmhgfs-only/inode.c:1920:7: note: in expansion of macro ‘hlist_for_each_entry’ hlist_for_each_entry(dentry, ^ include/linux/kernel.h:834:48: warning: initialization makes pointer from integer without a cast const typeof( ((type *)0)->member ) *__mptr = (ptr); \ ^ include/linux/list.h:687:40: note: in expansion of macro ‘container_of’ #define hlist_entry(ptr, type, member) container_of(ptr,type,member) ^ include/linux/list.h:698:15: note: in expansion of macro ‘hlist_entry’ ____ptr ? hlist_entry(____ptr, type, member) : NULL; \ ^ include/linux/list.h:710:13: note: in expansion of macro ‘hlist_entry_safe’ pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member)) ^ /tmp/modconfig-Etbo2b/vmhgfs-only/inode.c:1920:7: note: in expansion of macro ‘hlist_for_each_entry’ hlist_for_each_entry(dentry, ^ In file included from include/linux/compiler-gcc.h:106:0, from include/linux/compiler.h:54, from include/uapi/linux/stddef.h:1, from include/linux/stddef.h:4, from ./include/uapi/linux/posix_types.h:4, from include/uapi/linux/types.h:13, from include/linux/types.h:5, from /tmp/modconfig-Etbo2b/vmhgfs-only/./shared/driver-config.h:71, from /tmp/modconfig-Etbo2b/vmhgfs-only/inode.c:26: include/linux/compiler-gcc4.h:14:34: error: ‘union <anonymous>’ has no member named ‘d_alias’ #define __compiler_offsetof(a,b) __builtin_offsetof(a,b) ^ include/linux/stddef.h:17:31: note: in expansion of macro ‘__compiler_offsetof’ #define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER) ^ include/linux/kernel.h:835:29: note: in expansion of macro ‘offsetof’ (type *)( (char *)__mptr - offsetof(type,member) );}) ^ include/linux/list.h:687:40: note: in expansion of macro ‘container_of’ #define hlist_entry(ptr, type, member) container_of(ptr,type,member) ^ include/linux/list.h:698:15: note: in expansion of macro ‘hlist_entry’ ____ptr ? hlist_entry(____ptr, type, member) : NULL; \ ^ include/linux/list.h:710:13: note: in expansion of macro ‘hlist_entry_safe’ pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member)) ^ /tmp/modconfig-Etbo2b/vmhgfs-only/inode.c:1920:7: note: in expansion of macro ‘hlist_for_each_entry’ hlist_for_each_entry(dentry, ^ scripts/Makefile.build:257: recipe for target '/tmp/modconfig-Etbo2b/vmhgfs-only/inode.o' failed make[2]: *** [/tmp/modconfig-Etbo2b/vmhgfs-only/inode.o] Error 1 make[2]: *** 未完了のジョブを待っています.... Makefile:1333: recipe for target '_module_/tmp/modconfig-Etbo2b/vmhgfs-only' failed make[1]: *** [_module_/tmp/modconfig-Etbo2b/vmhgfs-only] Error 2 make[1]: Leaving directory '/usr/src/linux-headers-3.16.0-031600-generic' Makefile:120: recipe for target 'vmhgfs.ko' failed make: *** [vmhgfs.ko] Error 2 make: Leaving directory '/tmp/modconfig-Etbo2b/vmhgfs-only' The filesystem driver (vmhgfs module) is used only for the shared folder feature. The rest of the software provided by VMware Tools is designed to work independently of this feature.
どうやらこういうことらしい。
http://qiita.com/maccotsan/items/fafdc01deac71c20bd60
qnighy氏によればそのままでは上手く動かなかったらしいので、その辺も含めて調べてみる
ちなみに、/usr/lib/vmware-tools/modules/source/vmhgfs.tarを展開してパッチを当てて再圧縮して同じファイルに保存して……を繰り返してた (もちろん、もとのvmhgfsは保存しておく)
— Masaki Hara (@qnighy) 2015, 3月 10
一応成功したので記載しておく
実行環境
ホスト:Windows 8.1
ゲスト:Xubuntu 14.10-2
カーネルバージョン:3.16.0-031600-generic
VMware Player 7.1
VMwareTools9.9.2-2496486