LCD-8000UをLinuxで使う(遅まきながら)
お久しぶりです。
ちょっと仕事に没頭しているうちに、DisplayLinkまわりが偉いことになっていてビックリしました。
[Phoronix] DisplayLink Provides USB GPU Support On Linux
[Phoronix] DisplayLink's Frame-buffer and X.Org Drivers
[Phoronix] DisplayLink Linux Driver Continues To Mature
あっさりFrameBufferのモジュールが開発されて、それを使ってはいるもののX Windowのドライバまで提供されているんですね。
ちょっとX Windowは面倒臭そうだったので、FrameBufferを試してみることにしました。
試すのはFrameBufferのモジュールであるudlfb。
バージョンは6/10に出たばかりの0.2.3です。
まずはソースファイルの展開。今回欲しいのはudlfbのソースだけなので、そこだけ解凍します。
% tar xvf ~/down/udlfb-0.2.3_and_xf86-video-displaylink-0.3.tar.gz udlfb udlfb/ udlfb/README udlfb/Makefile udlfb/udlfb.c udlfb/udlfb.h
で早速コンパイル。モジュールを作成することになるので、Linuxカーネルのヘッダが必要になります。Ubuntuだとlinux-headersとかそこらへんです。
% make make -C /lib/modules/`uname -r`/build SUBDIRS=/tmp/udlfb modules make[1]: ディレクトリ `/usr/src/linux-headers-2.6.28-13-generic' に入ります Building modules, stage 2. MODPOST 1 modules make[1]: ディレクトリ `/usr/src/linux-headers-2.6.28-13-generic' から出ます
カレントディレクトリにudlfb.koができていればコンパイル成功。早速モジュールをカーネルに組み込みます。
% sudo insmod udlfb.ko
まあ、何も言われませんがな。これでフレームバッファが新しくできたことになります。
では早速/dev/fb0をば・・・とすると、全然存在しないでやんの。
% ls /dev/fb* ls: /dev/fb*にアクセスできません: No such file or directory
「なんでだろう?」と/var/log/messagesを見るとこんなメッセージが。
DisplayLink device attached ret control msg 0: 4 1501fffffff0 EDID XRES 800 YRES 600 INIT VIDEO 0 800 480 INIT VIDEO 1 1024 768 INIT VIDEO 2 1280 1024 INIT VIDEO 3 1400 1050 udlfb: probe of 2-3.1.1.3:1.0 failed with error -12 usbcore: registered new interface driver udlfb VMODES initialized
なんか解像度が未対応でエラーになっているっぽい。
解像度が800x480, 1024x768, 1280x1024, 1400x1050にしか対応していないのね。
これでは困るので800x600に対応させてみる。
解像度のキモになるのはudlfb.hで定義されているdlfb_init_modes()
void dlfb_init_modes(void) { dlfb_video_modes[0].col = 0; memcpy(&dlfb_video_modes[0].hclock, "\x20\x3C\x7A\xC9", 4); memcpy(&dlfb_video_modes[0].vclock, "\xF2\x6C\x48\xF9", 4); memcpy(&dlfb_video_modes[0].unknown1, "\x70\x53\xFF\xFF\x21\x27", 6); dlfb_video_modes[0].xres = 800; memcpy(&dlfb_video_modes[0].unknown2, "\x91\xF3\xFF\xFF\xFF\xF9", 6); dlfb_video_modes[0].yres = 480; memcpy(&dlfb_video_modes[0].unknown3, "\x01\x02\xC8\x19", 4); dlfb_video_modes[1].col = 0; memcpy(&dlfb_video_modes[1].hclock, "\x36\x18\xD5\x10", 4); memcpy(&dlfb_video_modes[1].vclock, "\x60\xA9\x7B\x33", 4); memcpy(&dlfb_video_modes[1].unknown1, "\xA1\x2B\x27\x32\xFF\xFF", 6); dlfb_video_modes[1].xres = 1024; memcpy(&dlfb_video_modes[1].unknown2, "\xD9\x9A\xFF\xCA\xFF\xFF", 6); dlfb_video_modes[1].yres = 768; memcpy(&dlfb_video_modes[1].unknown3, "\x04\x03\xC8\x32", 4); dlfb_video_modes[2].col = 0; memcpy(&dlfb_video_modes[2].hclock, "\x98\xF8\x0D\x57", 4); memcpy(&dlfb_video_modes[2].vclock, "\x2A\x55\x4D\x54", 4); memcpy(&dlfb_video_modes[2].unknown1, "\xCA\x0D\xFF\xFF\x94\x43", 6); dlfb_video_modes[2].xres = 1280; memcpy(&dlfb_video_modes[2].unknown2, "\x9A\xA8\xFF\xFF\xFF\xF9", 6); dlfb_video_modes[2].yres = 1024; memcpy(&dlfb_video_modes[2].unknown3, "\x04\x02\x60\x54", 4); dlfb_video_modes[3].col = 0; memcpy(&dlfb_video_modes[3].hclock, "\x42\x24\x38\x36", 4); memcpy(&dlfb_video_modes[3].vclock, "\xC1\x52\xD9\x29", 4); memcpy(&dlfb_video_modes[3].unknown1, "\xEA\xB8\x32\x60\xFF\xFF", 6); dlfb_video_modes[3].xres = 1400; memcpy(&dlfb_video_modes[3].unknown2, "\xC9\x4E\xFF\xFF\xFF\xF2", 6); dlfb_video_modes[3].yres = 1050; memcpy(&dlfb_video_modes[3].unknown3, "\x04\x02\x1E\x5F", 4); }
うん、さっぱり分からん数値の羅列ですな。分かるのはxres, yresのところぐらいですが、試しに480のところを600にしてみましたが、画面が乱れて使い物にならん。
さすがに手詰まりかなと思ったのですが、次の貴重な情報が私を再び突き動かします。
もし標準で対応している解像度以外を使いたい場合、libdlo で対応している解像度であれば、ソースを書き換えて対応させることは可能です。
で、tubecable 0.1.4の中のソースコードを参考にして、800x600用の定義を作ることにしました。
% tar xvf ~/down/tubecable_0.1.4.tar.gz tubecable/ tubecable/Makefile tubecable/tubecable.h tubecable/tubecable_demo.cpp tubecable/tubecable_huffman.bin tubecable/tubecable.cpp tubecable/tubecable_decrypt.cpp tubecable/tubecable_huffman.cpp
見るべきなのはtubecable.hのDL_REG_MODE_...となっている箇所。LCD-8OO0Uなら次の行ですね。
#define DL_REG_MODE_800x600_60 { 0x00, 0x20, 0x3c, 0x7a, 0xc9, 0x93, 0x60, 0xc8, 0xc7, 0x70, 0x53, 0xff, 0xff, 0x21, 0x27, 0x03, 0x20, 0x91, 0x8f, 0xff, 0xff, 0xff, 0xf2, 0x02, 0x58, 0x01, 0x02, 0x40, 0x1f }
これを参考に、dlfb_init_modes()に一つモードを追加してみます。
直すのは2ヶ所、どちらもudlfb.hの中身です。
最初はモードの数を示す定数。今は4になっているので5にしてみます。
#define MAX_VMODES 4
次にdlfb_init_modes()の中身を次みたいに変更します。
void dlfb_init_modes(void) { dlfb_video_modes[0].col = 0; memcpy(&dlfb_video_modes[0].hclock, "\x20\x3C\x7A\xC9", 4); memcpy(&dlfb_video_modes[0].vclock, "\xF2\x6C\x48\xF9", 4); memcpy(&dlfb_video_modes[0].unknown1, "\x70\x53\xFF\xFF\x21\x27", 6); dlfb_video_modes[0].xres = 800; memcpy(&dlfb_video_modes[0].unknown2, "\x91\xF3\xFF\xFF\xFF\xF9", 6); dlfb_video_modes[0].yres = 480; memcpy(&dlfb_video_modes[0].unknown3, "\x01\x02\xC8\x19", 4); dlfb_video_modes[1].col = 0; memcpy(&dlfb_video_modes[1].hclock, "\x36\x18\xD5\x10", 4); memcpy(&dlfb_video_modes[1].vclock, "\x60\xA9\x7B\x33", 4); memcpy(&dlfb_video_modes[1].unknown1, "\xA1\x2B\x27\x32\xFF\xFF", 6); dlfb_video_modes[1].xres = 1024; memcpy(&dlfb_video_modes[1].unknown2, "\xD9\x9A\xFF\xCA\xFF\xFF", 6); dlfb_video_modes[1].yres = 768; memcpy(&dlfb_video_modes[1].unknown3, "\x04\x03\xC8\x32", 4); dlfb_video_modes[2].col = 0; memcpy(&dlfb_video_modes[2].hclock, "\x98\xF8\x0D\x57", 4); memcpy(&dlfb_video_modes[2].vclock, "\x2A\x55\x4D\x54", 4); memcpy(&dlfb_video_modes[2].unknown1, "\xCA\x0D\xFF\xFF\x94\x43", 6); dlfb_video_modes[2].xres = 1280; memcpy(&dlfb_video_modes[2].unknown2, "\x9A\xA8\xFF\xFF\xFF\xF9", 6); dlfb_video_modes[2].yres = 1024; memcpy(&dlfb_video_modes[2].unknown3, "\x04\x02\x60\x54", 4); dlfb_video_modes[3].col = 0; memcpy(&dlfb_video_modes[3].hclock, "\x42\x24\x38\x36", 4); memcpy(&dlfb_video_modes[3].vclock, "\xC1\x52\xD9\x29", 4); memcpy(&dlfb_video_modes[3].unknown1, "\xEA\xB8\x32\x60\xFF\xFF", 6); dlfb_video_modes[3].xres = 1400; memcpy(&dlfb_video_modes[3].unknown2, "\xC9\x4E\xFF\xFF\xFF\xF2", 6); dlfb_video_modes[3].yres = 1050; memcpy(&dlfb_video_modes[3].unknown3, "\x04\x02\x1E\x5F", 4); dlfb_video_modes[4].col = 0; memcpy(&dlfb_video_modes[4].hclock, "\x20\x3C\x7A\xC9", 4); memcpy(&dlfb_video_modes[4].vclock, "\x93\x60\xC8\xC7", 4); memcpy(&dlfb_video_modes[4].unknown1, "\x70\x53\xFF\xFF\x21\x27", 6); dlfb_video_modes[4].xres = 800; memcpy(&dlfb_video_modes[4].unknown2, "\x91\x8F\xFF\xFF\xFF\xF2", 6); dlfb_video_modes[4].yres = 600; memcpy(&dlfb_video_modes[4].unknown3, "\x01\x02\x40\x1F", 4); }
変更したのは最後の10行ぐらいの部分。
後は再度コンパイルして、再度insmodすると・・・
DisplayLink device attached ret control msg 0: 4 1501fffffff0 EDID XRES 800 YRES 600 INIT VIDEO 0 800 480 INIT VIDEO 1 1024 768 INIT VIDEO 2 1280 1024 INIT VIDEO 3 1400 1050 INIT VIDEO 4 800 600 ret control msg 1 (STD_CHANNEL): 16 ret bulk 2: 156 156 ret bulk 3: 0 found valid mode...20000 screen base allocated !!! colormap allocated Console: switching to colour frame buffer device 100x37 usbcore: registered new interface driver udlfb VMODES initialized
おおっ、なんか動いた感じ。
% ls /dev/fb*
/dev/fb0
ちゃんとFrameBufferも作られてますね。
とりあえず今日はこれで満足します。
せっかくできたFrameBufferを何に使うかは明日以降ゆっくり考えよう・・・。