N900内蔵FMラジヲを日本向けの周波数帯にしようと試行錯誤した記録。
結論から言うと、周波数帯の変更には成功しましたが、受信は出来てません。
成功編は未定。
試行錯誤の道程*1
- FMRadio.pyを読んでみる
- /sys/class/i2c-adapter/i2c-3/3-0022/以下をいじってみる
- FMRadio.pyとFMRadioUI.pyを改変してみる
- fmコマンドだとかradioコマンドだとかを試してみる
*1
たたたっ高村光太郎ちゃうわ!
わかったこと
さて、(たしかN800のFMラジオ界隈でも活躍されてた)Martin Grimmeさん(pycage)の
直球ネームアプリケーション、"FMRadio"のソースを読む限り、N900では改変カーネルを焼く必要は無いようです。
そのかわり、sysfs(/sys/以下)を適切にいじってやることでリージョンの設定が出来ます。
具体的に述べていくと
/sys/class/i2c-adapter/i2c-3/3-0022/region
に国別のコードnを書き込むわけです。[n=0,1,2,3,4]
このコードnはカーネルソース中
drivers/media/radio/radio-bcm2048.cに定義されており、抄出すれば
/* USA */つまり日本向けの周波数にしたいなら、ルート権限で
{
.channel_spacing = 20,
.bottom_frequency = 87500,
.top_frequency = 108000,
.deemphasis = 75,
.region = 0,
},
/* Australia */
{
.channel_spacing = 20,
.bottom_frequency = 87500,
.top_frequency = 108000,
.deemphasis = 50,
.region = 1,
},
/* Europe */
{
.channel_spacing = 10,
.bottom_frequency = 87500,
.top_frequency = 108000,
.deemphasis = 50,
.region = 2,
},
/* Japan */
{
.channel_spacing = 10,
.bottom_frequency = 76000,
.top_frequency = 90000,
.deemphasis = 50,
.region = 3,
},
/* Japan wide band */
{
.channel_spacing = 10,
.bottom_frequency = 76000,
.top_frequency = 108000,
.deemphasis = 50,
.region = 4,
},
echo 3 > /sys/class/i2c-adapter/i2c-3/3-0022/regionだとか
echo 4 > /sys/class/i2c-adapter/i2c-3/3-0022/regionとすればよく、実際にやってみると /sys/class/i2c-adapter/i2c-3/3-0022/以下
region_bottom_frequencyとregion_top_frequencyが上記の抄出範囲で定義された値になっていることが確認できます。
このうえで、リージョン決め打ちのFMRadio*2を少々改造します。
改造したのは/opt/fmradio/components/fmradio/以下FMRadio.pyとソースtarボールから抽出し、同ディレクトリに放りこんだFMRadioUI.py。
FMRadio.pyは258行目付近と268行目付近に追記およびコメントアウト
# return self.FM_BAND_EUR
return self.FM_BAND_JPN
# band = self.FM_BAND_EURFMRadioUI.pyは124行目付近に追記およびコメントアウト。
band = self.FM_BAND_JPN
# self.__fmscala.set_range(87500, 108000)
self.__fmscala.set_range(76000, 108000)
ここでコマンドラインからFMRadioを起動し、前出の方法でリージョンコードを4に書き換えてから、なるだけ素早くFMRadioを再起動。*3
指針は76.0Mhzを指し、成功か。と思いきや87.5Mhz以上でしか正常に選局できない。
エラー出力を読むと、V4l2インターフェースの_VIDIOC_S_FREQUENCYへの書き込みに失敗している。。。
改造*5がまずいんだろうか、気を取り直して、次へ進む。
さて、N900のFMラジオにはv4lのAPIを使って、/dev/radio1経由でアクセスできます。
と言うことはつまり、TVカードにFMラジオが乗っていた頃からのソフトウェア資産がそのまま利用できる。素晴らしきかなLinux!
コンパイルも面倒なのでdebianのリポジトリから適当にバイナリをとってくる。素晴らしきかなDebian!
(以下の操作は裏でFMRadioを起動し、リージョンを書き換えてから行っています。)
数あるラジオ関連ツールの中から、初めに試したのはFMRadioに勝るとも劣らないド直球ネームのradio。
特にエラーメッセージも出ないので、次にfmtoolsを試してみる。
コマンドラインから
fm -d /dev/radio1 xx.xするとまた出た!_VIDIOC_S_FREQUENCYのI/Oエラー!
ひょっとして、これはドライバのバグなんですかねぇ。
参考までにv4l-info /dev/radio1の出力(一部)は
### v4l2 device info [/dev/radio1] ###こんな感じ。
general info
VIDIOC_QUERYCAP
driver : "bcm2048"
card : "Broadcom bcm2048 FM Radio Recei"
bus_info : "I2C: 0x22"
version : 0.0.1
capabilities : 0x50400 [?,TUNER,?]
standards
inputs
tuners
VIDIOC_G_TUNER(0)
index : 0
name : "FM Receiver"
type : RADIO
capability : 0x11 [LOW,STEREO]
rangelow : 1216000
rangehigh : 1728000
rxsubchans : 0x2 [STEREO]
audmode : STEREO
signal : 0
afc : 0
rangelowおよびrangehighは16で割ればそれぞれ76000/108000であり、一応適切に設定されているようだ。
*2
将来的にはsysfsから読んでくれるようになるらしい。
set_fm_band(self, band)なる未使用関数が有ったり、着々と進歩している。いろいろと頭の下がる思いです。
*3
なぜこんな面倒な手順をとるかというと、
FMRadioを起動すると同時にカーネルモジュールradio-bcm2048.koが読み込まれ、デバイスノードや/sys/class/i2c-adapter/i2c-3/3-0022/以下が作成される訳ですが、FMRadioは起動時にv4l2インターフェースから周波数帯の上限と下限を読み込むので、リージョンコードの書き換えをFMRadioに反映させるためにはFMRadioをいったん終了し、(多分/usr/libexec/n900-fmrx-enablerあたりが)カーネルモジュールをアンロードする前に、もう一度FMRadioを起動するという手順を踏む必要があるからです。復文長い。
ちなみに/etc/modprobe.d/を使ってradio_bcm2048.koのロード時に
リージョンコードを書き込む様に設定*4してみましたが、FMRadioによるロードではそれらの設定は無視されてしまいました。
というわけでFMRadio.pyの__init__内でos.systemとsudo echoを組み合わせて使うのが消極的かつそこそこマシな自動化だろうか。
*4
/etc/modprobe.d/radio-rx-jpnとして以下の内容のファイルを作成
install radio_bcm2048 /sbin/modprobe --ignore-install radio_bcm2048 && echo 4 > /sys/class/i2c-adapter/i2c-3/3-0022/region
*5
ざざざっ雑誌ちゃうわ!久米田康治やわ!
蛇足
FM送信機(/dev/radio0)の周波数帯を日本向けにしたい場合
/sys/class/i2c-adapter/i2c-2/2-0063/regionに上記と同じく3か4の値を書き込みます。
が、それだけでは設定UIは87.5Mhz〜108.0Mhzのままです。
周波数帯は決め打ちになっているのか、はたまたシステムのロケールにしたがって変更されるのか。
なかなか一筋縄には行きませんな。だがそれが良い。