問題にぶつかる前に、ioctlを知っていたので、原因を追うことができた。
LinuxDeviceDriver が役に立ったと実証できたはずだ。


正直、
これが、CyanogenModのバグだったら、バグレポートをすることで、OSSのコミュニティに関われるかも・・・
と期待しながらこの問題を調べていった。
結果がこの様な有様でがっかりだった。

CyanogenModでなくても、どこかに参加できたらなぁ。

6.1.0RC1について

この記事の主題とは関係ないが、6.1.0RC1と6.0.0の違いとしては、
ボイスレコーダのインターフェースが変わっていて使いやすくなっていたことと、
file managerが追加されていた。
初めて入れたのが自分でビルドした6.1.0RC1だった上に、リリースノートを確認していないので、気づいた違いはそれくらいだった。


せっかくなので、vncserverを起動させて、PCでキャプチャした画像を載せます。
上がバージョン情報で、下がカメラをキャプチャした画像。
動画を載せれたらよかったのかもしれないけど、映したいものが無かった。
これでは、720Pはまったく伝わらないな・・・

ソースビルドについて

2ヶ月くらい前に NexusOne を手に入れて、CyanogenMod をソースビルドして入れてみたら、カメラが動かなかった。
原因を追ったら、手間がやたらとかかったので記録しておく。

ビルドしたCyanogenModはupdate-cm-6.1.0-RC1-N1-signedで、
repo syncを初めてしたのは11月1日くらいだったと思う。
ビルドは本家の説明のとおりにしたつもりだった。


現象は、
カメラを起動したら、真っ暗のままで何も表示されず、固まったようだった。
HOMEボタンを何度か押すと復帰できた。


原因は、
ビルド時にプロプライエタリなバイナリをNexusOneから取り出す./extract-files.shを実行する際に、
取り出す対象の端末に入っているliboemcamera.soが720Pに対応していなかったためだった。


解決策は、
配布されているupdate-cm-6.0.0-N1-signed.zipを素直に入れてから、バイナリを取り出せばいい。


調べた経緯を書いていく。
カメラを起動したときのログをとると下記が出てきた。

11-16 01:15:28.040 D/dalvikvm(  158): GC_EXTERNAL_ALLOC freed 13339 objects / 690480 bytes in 66ms
11-16 01:15:28.080 E/mm-camera(  120): main: MSM_CAM_IOCTL_REGISTER_PMEM ioctl failed for MSM_PMEM_AF type. ioctl return value is 4294967295 
11-16 01:15:28.080 E/mm-camera(  120): isp3a_init_ctrl failed
11-16 01:15:32.140 W/WindowManager(  158): App freeze timeout expired.

E/mm-cameraのメッセージを、frameworksやhardware, deviceのなかでgrepしても、ソースが見つからなかった。
MSM_CAM_IOCTL_REGISTER_PMEMでgrepをかけたところ、kernelソース以外で怪しいところとしては、
hardware/msm7k/libcamera2/QualcommCameraHardware.cppがでてきた。
それと、liboemcamera.soでも使っている。
MSM_CAM_IOCTL_REGISTER_PMEM は、ioctlのパラメータとして使用しており、REGISTERとあるので、カーネル領域のメモリを確保しているようだ。

ここで、libcamera.soでも、liboemcamera.soでもカーネル領域を確保しているため、割り当てに失敗しているかと考えて、カーネルログをみた。
しかし、下記のようにエラーらしいエラーは見つからなかった。

<6>[  316.639099] msm_open_common: open control0
<6>[  316.789611] >>>>>>>>(2010-11-21 03:59:07.865182928 UTC)<<<<<<<
<6>[  316.790252] msm_open_common: open config0
<6>[  316.814575] msm_release_config: config0
<6>[  316.815246] __msm_release:sync->opencnt:2 
<6>[  316.815856] release config atomic_set pmsm->opened as 0

ここで行き詰まって、6.0.0の出来合いのイメージを入れてみたら、カメラが正常に動くことを確認した。

次に、QualcommCameraHardware.cppにgit blameをかけて、MSM_CAM_IOCTL_REGISTER_PMEMを使っている関数register_bufの更新日を見たところ、下記のように 2010-06-28 21:34:03 とでた。
6.0.0がリリースされたのが8月なので、libcamera.so はシロであるとわかった。
ちなみに、libcamera.so にMSM_CAM_IOCTL_REGISTER_PMEMでgrepをかけても、何も出てこないのは、バイナリをstripしているためだと思う。

6b4906b6 (Michael Casadevall 2010-01-12 19:05:16 -0500 1845)     pmemBuf.type     = pmem_type;
6b4906b6 (Michael Casadevall 2010-01-12 19:05:16 -0500 1846)     pmemBuf.fd       = pmempreviewfd;
6b4906b6 (Michael Casadevall 2010-01-12 19:05:16 -0500 1847)     pmemBuf.offset   = offset;
6b4906b6 (Michael Casadevall 2010-01-12 19:05:16 -0500 1848)     pmemBuf.len      = size;
6b4906b6 (Michael Casadevall 2010-01-12 19:05:16 -0500 1849)     pmemBuf.vaddr    = buf;
6b4906b6 (Michael Casadevall 2010-01-12 19:05:16 -0500 1850)     pmemBuf.y_off    = 0;
6b4906b6 (Michael Casadevall 2010-01-12 19:05:16 -0500 1851)     pmemBuf.cbcr_off = size * 2 / 3; //PAD_TO_WORD(size * 2 / 3);
38f3ad1b (Eddie Ringle       2010-06-28 21:34:03 -0400 1852)     pmemBuf.vfe_can_write   = true;
6b4906b6 (Michael Casadevall 2010-01-12 19:05:16 -0500 1853) 
6b4906b6 (Michael Casadevall 2010-01-12 19:05:16 -0500 1854)     LOGV("register_buf: camfd = %d, reg = %d buffer = %p",
6b4906b6 (Michael Casadevall 2010-01-12 19:05:16 -0500 1855)          camfd, !register_buffer, buf);
6b4906b6 (Michael Casadevall 2010-01-12 19:05:16 -0500 1856)     if (ioctl(camfd,
6b4906b6 (Michael Casadevall 2010-01-12 19:05:16 -0500 1857)               register_buffer ?
6b4906b6 (Michael Casadevall 2010-01-12 19:05:16 -0500 1858)               MSM_CAM_IOCTL_REGISTER_PMEM :
6b4906b6 (Michael Casadevall 2010-01-12 19:05:16 -0500 1859)               MSM_CAM_IOCTL_UNREGISTER_PMEM,
6b4906b6 (Michael Casadevall 2010-01-12 19:05:16 -0500 1860)               &pmemBuf) < 0) {
6b4906b6 (Michael Casadevall 2010-01-12 19:05:16 -0500 1861)         LOGE("register_buf: MSM_CAM_IOCTL_(UN)REGISTER_PMEM fd %d error %s",
6b4906b6 (Michael Casadevall 2010-01-12 19:05:16 -0500 1862)              camfd,
6b4906b6 (Michael Casadevall 2010-01-12 19:05:16 -0500 1863)              strerror(errno));
6b4906b6 (Michael Casadevall 2010-01-12 19:05:16 -0500 1864)         return false;
6b4906b6 (Michael Casadevall 2010-01-12 19:05:16 -0500 1865)     }
6b4906b6 (Michael Casadevall 2010-01-12 19:05:16 -0500 1866)     return true;
6b

また行き詰まったので、grepを、E/mm-cameraのエラーメッセージで、ソース全体にかけたところ、liboemcamera.soがでてきた。
この時点で、熟練した開発者なら、ビルド手順に問題があったことに気づいただろう。
そもそも、この様な間違いはしない気がする。

自分は何もピンとこなかったため、ioctlで-1(0xFFFFFFFF)が返されているので、カーネルソースを見ることにした。
MSM_CAM_IOCTL_REGISTER_PMEMを利用していて、一番関係がありそうなのは、
kernel-msm/drivers/media/video/msm/msm_camera.c だった。
利用している関数は、下記になる。

static long msm_ioctl_common(struct msm_device *pmsm,
		unsigned int cmd,
		void __user *argp)
{
	CDBG("%s\n", __func__);
	switch (cmd) {
	case MSM_CAM_IOCTL_REGISTER_PMEM:
		return msm_register_pmem(pmsm->sync, argp);
	case MSM_CAM_IOCTL_UNREGISTER_PMEM:
		return msm_pmem_table_del(pmsm->sync, argp);
	default:
		return -EINVAL;
	}
}

CDBGが抑制されていることがわかったが、make menuconfigでみてもログを出す項目は無かった。
今振り返ると、menuonfigでみた.config は、自分でビルドした6.1.0の/proc/config.gzだったため、出来合いの6.0.0でみたらあるかもしれない。
CDBGの定義を見ると、下記のとおりだった。

#ifdef CONFIG_MSM_CAMERA_DEBUG
#define CDBG(fmt, args...) printk(KERN_INFO "msm_camera: " fmt, ##args)
#else
#define CDBG(fmt, args...) do { } while (0)
#endif

そこで、CONFIG_MSM_CAMERA_DEBUGをソースに直接定義して、自分でいくつかログを埋め込んでビルドをし直した。
カーネルのビルドは、ここを参考にした。
カーネルビルドしてから、ソース全体をビルドしたら、kernel_msmをclean(make mrproper)しろと言われたので、トップディレクトリでmakeをするだけでよかったかもしれない。

決め手になったカーネルログは、下記のとおり。

<6>[  111.912475] msm_camera: msm_ioctl_common: cmd1074031874:
<6>[  111.912811] msm_camera: __msm_register_pmem:infotype:7
<6>[  111.913452] msm_camera: __msm_register_pmem:other
<6>[  111.913787] msm_camera: msm_ioctl_config: cmd 2 DONE

liboemcamera.so は、MSM_PMEM_AF(7)を渡したといっているのに、kernelドライバは無効パラメータ(other)と判断している。
MSM_PMEM_AFの定義は、kernel-msm/include/media/msm_camera.hにあった。

#ifdef CONFIG_720P_CAMERA
・
・
・
#define MSM_PMEM_AF           6
#define MSM_PMEM_AEC          7
・
・
・
#else
・
・
・
#define MSM_PMEM_AEC_AWB		6
#define MSM_PMEM_AF			7

と、CONFIG_720P_CAMERAで振り分けられていて、
ここで、liboemcamera.soがおかしいと気づいた。

適当に探した6月9日の記事では、froyoでは720Pに対応していないとあった。
CONFIG_720P_CAMERAを無効にしたら動くとも思ったが、
別のプロプライエタリなバイナリも同じような爆弾を抱えていそうだったため、とりあえず6.0.0をバイナリの抽出元にして、再度ビルドをしたら、
カメラも動いた。

720Pになっているかは、いままでろくにカメラを使ったことがなかったためわからないが、/proc/config.gz の CONFIG_720P_CAMERA は有効になっているので、720Pで動いているのだと思う。

カーネルの本と一緒に買って読みはじめた。
続くか分からないが、メモを残しておく。
日記の編集は無粋だが、記事が複数になると後で見返しづらいので、この記事は校正を続けると思う。

環境

  • ubuntu 9.10
  • 2.6.31-15-generic

サンプルソースコード

下記にあったが、古くてコンパイルが通らなかった。
http://examples.oreilly.com/9780596005900/

以下わかったことを記録していく。

kernel ソースコードの変更点
  • は無くなった。
  • struct task_structにuid,euidのメンバがない
    • credメンバの下にある
  • .../scull/Makefile". Fix it to use EXTRA_CFLAGS
    • KBUILD_NOPEDANTIC = 1
コード誤植?
  • scull.init:line 91〜94: $DEVICE.o → $DEVICE.ko
    • この値を insmod しているので、やはり .o ではなく、.ko だと思う
    • .koって本質はなんだろう

これでカーネル、モジュールの勉強になるのだろうか

cronを使い、gnomeの設定を変更して壁紙を変えることをしていたが、一年程前から動かなくなっていた。
スクリプトは、RESTぶるさんのGNOME用壁紙チェンジャーをこっそり使わせてもらっていた。
gconftool-2を使って壁紙を変えている。

現象としては、コマンドでは普通に動くのに、cronで起動すると動かない。
動かないとは、.gconf以下の対象のxmlは変更されているにもかかわらず、壁紙は変わらず、gconf-editorにも変化がない。

動かなくなった原因は、 このバグレポート にあるとおり。

  • この挙動は仕様どおりだそう。
  • gconftool-2 と gconfd のプロセス間通信には CORBA を使っていたが、D-Bus に変更したらしい。
  • D-Bus を使うには、DBUS_SESSION_BUS_ADDRESS が必要らしい。
  • gconftool-2 を起動する cron は、DBUS_SESSION_BUS_ADDRESSを知らないので、通信に失敗するらしい。
  • gconftool-2 --ping の終了ステータスで、失敗を確認できる。
  • cron に DBUS_SESSION_BUS_ADDRESS を教えると起動できるようになるらしい。

上記リンク先のリンク先では、DISPLAY=:0.0 で起動に成功したという報告があったが、自分の環境では失敗した。
対応としては、いただいたソース中の gconftool-2 起動前に、下記を挿入した。

USER = (`whoami`).chomp!

FILES = Dir.glob("/home/#{USER}/.dbus/session-bus/*")
File::open(FILES[0], File::RDONLY){ |f|
  f.each{|line|
    if /^DBUS_SESSION_BUS_ADDRESS=(.*)$/ =~ line
        DBUS_SESSION_BUS_ADDRESS=$1
    end
  }
}
ENV["DBUS_SESSION_BUS_ADDRESS"]=DBUS_SESSION_BUS_ADDRESS


一年もたって解決しようとしたきっかけは、Desktop Drapesという壁紙自動変更アプリだ。
Desktop Drapes が楽しそうだったので、インストールしてみたのだが、MonoがCPUリソースを食うだけで動かなかった。
そこで、壁紙チェンジャーを思いだし、修正してみることにした。

RESTぶるさん、当分使わせていただきます。
トラックバック初めてするので、変だったらお知らせください。

あれ、トラックバックできてない?

Last.fmのラジオサービスの課金について

8月2日にLast.fmからラジオサービス課金の知らせが届いた。
調べたら日本では、4〜5月くらいからすでに課金が始まっているらしい。

どうやら、自分のアカウントは、国籍を登録していないからか、
これまでサービスが停止されていなかったようだ。
(というかいまでも聞ける。)
課金開始の理由として英米独以外での広告収入が難しいということだったので、
英・米・独人っぽい国籍不明利用者は数ヶ月猶予を持たせてくれたのだろうか。

でたらめな情報でアカウントを取得している人も結構いると思うのだが、そこを厳密に調べるコストメリットがないのだろうか。

一月に一回くらいしかラジオサービスは利用しないので、なくてもそれほど困らないが、
結構自分にマッチする音楽を聞けるので、課金しようかと思う。でもめんどくさくてしないかも。

あと、主題からずれるが、Last.fm のいいところとしては、
たまに面識のないコミュニティのメンバからメールを受け取ることがあることだ。
送り主は、自作音楽やファンになっている音楽を薦めてきて、なかなか面白い。