SDHCドライバ現時点のまとめ

いやぁ、反響の大きさにびっくりです。
無線LANドライバとかWPA対応とかの時と同じ位か、それ以上ですね。

これだけ反響が大きいと、うれしい反面、少々恐くもあります。

元々32GB SD を持っていた方だけでなく、安くても約7000円、いいものであれば1万円以上するものを、買ってまで確認していただいた方もいらっしゃるようで、動かなかったときのことを考えるとちょっと恐ろしいです。

一応、出だしは好調のようですが、負荷をかけたり、いろんな使われ方をしているうちに問題が出てくる可能性もあり、そういったバグは再現しにくく、解決しづらい場合が多いので、まだまだ安心できません。

まぁ、ビビっていても先に進めないので、今のところの問題点や今後についてまとめてみたいと思います。

まずは動作状況から。ありがたいことに、今のところ不具合報告はありません or 解決済みです。

  • SL-Cxx00 – v2.0
    • SD – 1GB, 2GB, 4GB で今のところ問題なし
    • SDHC – 4GB, 8GB, 16GB, 32GB で今のところ問題なし
  • SL-C750/760/860 – v1.0
    • SD – 128MB, 256MB, 512MB, 1GB, 2GB, 4GB で今のところ問題なし
    • SDHC – 4GB で今のところ問題なし

 今のところわかってる問題点は以下の通りです。

  • 4GB以上のSD/SDHCに対してipkのインストール時に「アプリケーション追加先のメモリーが足りません」と表示される。 (SL-C3200を除く全ての機種)

これは以前、SL-C1000 で解析した 4GB SD にipk のインストールができない問題と同じです。空き容量の計算が大容量に対応していないためです。SL-C1000,3000の方は「qinstall修正パッチ」をインストールすることで解決します。

ipkがインストールできないのではSDHCの大容量も魅力が半減なので、そのほかの機種についても対応する予定で考えています。

今後についてですが、現在 SL-C750/760/860 用の 32GB 対応ドライバを開発中です。まだまだちゃんと動いてくれないので、もうちょっと時間がかかりそうです。

すでに困ってる人がいるという意味では、先にqinstall修正パッチを他の機種にも対応させた方がいいかもしれないですね。

ぼちぼち進めますので、少々お待ちください。

8GB SDHC認識 !?

またまたSDHC関係です。SL-C1000で4GBを超えるSDHCの認識に成功しました!

ただ、今回は前回とは違い、派手にバイナリパッチを当てているので、前回以上に危険です。

そのことを理解した上でお試しください。 → ダウンロードページ

8GB SDHCを認識
8GB SDHCを認識!!

今回の修正は以下の3点で行っています。

  • 容量計算処理
  • 読み込み処理 
  • 書き込み処理

しかも、それぞれSD, SDHC で処理が変わるので、修正したところ全てのルートを確認するのが結構難しいということもあり、一通り確認はしたつもりですが、正直、問題ないと言える自信はちょっとありません。

SL-C1000で以下のカードで確認を行いました。

  • GREEN HOUSE GH-SDCM1GC (miniSD 1GB)
  • アイオーデータ SDMC-2G (microSD 2GB)
  • Transcend TS4GSDC (SD 4GB)
  • Transcend TS4GSD133 (SD 4GB)
  • Sandisk SDSDQ-4096 (microSDHC 4GB)
  • A-DATA SDHC8GB (SDHC 8GB)
  • PCI PL-SDHC08G (SDHC 8GB)

確認した項目は以下です。

  1. 挿入後SDカードアイコンが表示されること
  2. 容量が正しく認識されていること
  3. あらかじめPCで書き込んでおいたファイルが見えること
  4. 上記ファイルを別名でSDにコピーし、エラーが出ないこと
  5. とりはずしてPCにて、コピー前と後のファイルをコンペアし、差分がないこと

また、8GB SDHC については、7GBと1GBの2つのパーテーションを作成し、後半の1GBに対してもマウント、ファイルの読み込み、ファイルの書き込み、アンマウントが問題なくできることを確認してます。

8GB以上の容量については持っていないので確認できてませんが、原理的には 32GB も認識できるハズです。

人柱になってもいいという方は、試していただけるとありがたいです。

そのときは動いても動かなくてもコメントいただけるとうれしいです。よろしくお願いします。

SDHC認識!(4GB限定)

SL-C1000 で 4GBのSDHCの認識に成功しました!

経過を書こうかと思っていたのですが、動いたのでとりあえず修正したドライバを公開します。 → ダウンロードページ

——–2010/01/26追記——–

ドライバをインストール後、再起動してください。

また、SL-C1000, 3000, 3100 をお使いの方で、tetsu さんのところで配布されている 4GB 対応 SD ドライバをインストールしている人はアンインストールしてからインストールしてください。

———————————–

一応動作確認はしましたが、 動作保証はできません。ご自身の責任でお試しください。

壊れてもいいから試してみたい!というチャレンジャーのみお試しください。
試された方は結果をコメントの方に書いていただけるとありがたいです。

注意事項としては、SDHC対応は4GBのみという点です。 8GB,16GB 等の SDHC は使用できません。絶対に差し込まないでください。

いままでは認識すらしなかったため、挿入してもそれほど害はありませんでしたが、4GBを超えるSDを入れると中途半端に認識してしまうため、中のデータを壊す可能性が高いです。

手持ちの以下のメディアで認識することを確認しました。今まで通り、ノーマルSDも使用できています。

  • SD 512MB
  • SD 2GB
  • SD 4GB
  • SDHC 4GB

4GBのみ対応というのはオリジナルのドライバの作り上、SDへのアクセスにブロック番号ではなく、32bit長のオフセットアドレスを用いているためです。32bit なので 4GB が上限となります。

これはオリジナルの作りが悪いというわけではなく、SDの仕様では32bitアドレス指定でREAD/WRITE する仕様のためです。これが SDHC では4GB以上の容量に対応するために、仕様上ブロック指定に変更されています。

上記の通り、READ/WRITE に関する関数はすべてアドレス指定で設計されており、4GBを超えるSDHCに対応するには、それらの関数すべてをブロック指定に修正する必要があります。ソースがあればまだ容易なのですが、ソースなしで関数の仕様を大幅に変更するのは非常に厳しいものがありますので、4GBを超えるSDHCのサポートはかなり困難です。

一応、解析は進めますが、今まで以上に可能性は低いと思ってください。

SDHCを使いたい!その2

まず SD と SDHC の違いをまとめると、以下の違いがあるようです。

  • 初期化フェーズのACMD41の前にCMD8(SEND_IF_COND)を実行する必要がある
  • ACMD41の送信時に、HCSビットを1にする必要がある
  • CMD9(SEND_CSD)のレスポンスのフォーマットがCSD v2.0になる
  • CMD17,18,24,25,32,33(READ, WRITE, ERASE)の引数がアドレス指定からブロック指定(1ブロック 512byte固定)になる

ドライバを改造するポイントとしては、初期化処理にCMD8送信とCSDデコードの修正を入れ、READ/WRITE処理でアドレスを512で割れば何とかなるかな??

ということで解析開始。

まずは readelf でシンボルをざっと見てみます。elf フォーマット自体はアーキテクチャ非依存なので、x86 ホストの readelf で ARM の elf バイナリのシンボルを見ることも可能です。

$ readelf -sW sharp_mmcsd_m.o 

とりあえず気になったシンボルは以下の通り

     86: 000032e0   448 FUNC    LOCAL  DEFAULT    1 sd_get_csd
134: 00006cb8 1212 FUNC LOCAL DEFAULT 1 pxa_sd_put_command
142: 00007188 480 FUNC LOCAL DEFAULT 1 pxa_sd_wait_response
143: 00007368 344 FUNC LOCAL DEFAULT 1 pxa_sd_wait_id_response
144: 000074c0 96 FUNC LOCAL DEFAULT 1 pxa_sd_get_response_value

この辺を突破口に解析を進めます。

まずはサイズが小さくて解析しやすそうな pxa_sd_get_response_value から。

$ arm-linux-objdump -Dr sharp_mmcsd_m.o
.....snip....
  000074c0 <pxa_sd_get_response_value>:
74c0: e1a0c00d mov ip, sp
74c4: e92dd800 stmdb sp!, {fp, ip, lr, pc}
74c8: e59f303c ldr r3, [pc, #3c] ; 750c <pxa_sd_get_response_value+0x4c>
74cc: e5932000 ldr r2, [r3]
74d0: e59f3038 ldr r3, [pc, #38] ; 7510 <pxa_sd_get_response_value+0x50>
74d4: e5802000 str r2, [r0]
74d8: e5932000 ldr r2, [r3]
74dc: e59f3030 ldr r3, [pc, #30] ; 7514 <pxa_sd_get_response_value+0x54>
74e0: e5802004 str r2, [r0, #4]
74e4: e5932000 ldr r2, [r3]
74e8: e59f3028 ldr r3, [pc, #28] ; 7518 <pxa_sd_get_response_value+0x58>
74ec: e5802008 str r2, [r0, #8]
74f0: e5932000 ldr r2, [r3]
74f4: e59f3020 ldr r3, [pc, #20] ; 751c <pxa_sd_get_response_value+0x5c>
74f8: e580200c str r2, [r0, #12]
74fc: e5932000 ldr r2, [r3]
7500: e24cb004 sub fp, ip, #4 ; 0x4
7504: e5802010 str r2, [r0, #16]
7508: e91ba800 ldmdb fp, {fp, sp, pc}
750c: 00000268 andeq r0, r0, r8, ror #4
750c: R_ARM_ABS32 .bss
7510: 0000026c andeq r0, r0, ip, ror #4
7510: R_ARM_ABS32 .bss
7514: 00000270 andeq r0, r0, r0, ror r2
7514: R_ARM_ABS32 .bss
7518: 00000274 andeq r0, r0, r4, ror r2
7518: R_ARM_ABS32 .bss
751c: 00000278 andeq r0, r0, r8, ror r2
751c: R_ARM_ABS32 .bss

これをC言語に直していきます。まず、関数の初めと終わりは4GSD へ ipk インストールの道 – その2にも書いたとおり、stmdb でレジスタを保存して、ldmdb でレジスタ復元&リターンをしています。なのでそれ以外の処理を解析します。

内容からC言語風の記述に直すと以下のようになります。

000074c0 <pxa_sd_get_response_value>:
74c0: e1a0c00d mov ip, sp
74c4: e92dd800 stmdb sp!, {fp, ip, lr, pc}
74c8: e59f303c ldr r3, [pc, #3c] ; 750c <pxa_sd_get_response_value+0x4c> // .bss + 0x268
74cc: e5932000 ldr r2, [r3]
74d0: e59f3038 ldr r3, [pc, #38] ; 7510 <pxa_sd_get_response_value+0x50>
74d4: e5802000 str r2, [r0]
// r0 しか使われていないので、引数は1つっぽいとりあえず arg0 と命名
arg0[0] = *(.bss + 0x268);

74d8: e5932000 ldr r2, [r3]
74dc: e59f3030 ldr r3, [pc, #30] ; 7514 <pxa_sd_get_response_value+0x54>
74e0: e5802004 str r2, [r0, #4]
// r0 のオフセットは 4 の倍数なので int か unsigned int っぽい
arg0[1] = *(.bss + 0x26c);

74e4: e5932000 ldr r2, [r3]
74e8: e59f3028 ldr r3, [pc, #28] ; 7518 <pxa_sd_get_response_value+0x58>
74ec: e5802008 str r2, [r0, #8]
arg0[2] = *(.bss + 0x270);

74f0: e5932000 ldr r2, [r3]
74f4: e59f3020 ldr r3, [pc, #20] ; 751c <pxa_sd_get_response_value+0x5c>
74f8: e580200c str r2, [r0, #12]
arg0[3] = *(.bss + 0x274);

74fc: e5932000 ldr r2, [r3]
7500: e24cb004 sub fp, ip, #4 ; 0x4
7504: e5802010 str r2, [r0, #16]
arg0[4] = *(.bss + 0x278);

7508: e91ba800 ldmdb fp, {fp, sp, pc}
return;

750c: 00000268 andeq r0, r0, r8, ror #4
750c: R_ARM_ABS32 .bss
7510: 0000026c andeq r0, r0, ip, ror #4
7510: R_ARM_ABS32 .bss
7514: 00000270 andeq r0, r0, r0, ror r2
7514: R_ARM_ABS32 .bss
7518: 00000274 andeq r0, r0, r4, ror r2
7518: R_ARM_ABS32 .bss
751c: 00000278 andeq r0, r0, r8, ror r2
751c: R_ARM_ABS32 .bss

C言語風記述だけを抜き出して、関数風にすると

void pxa_sd_get_response_value (int *arg0)
{
arg0[0] = *(.bss + 0x268);
arg0[1] = *(.bss + 0x26c);
arg0[2] = *(.bss + 0x270);
arg0[3] = *(.bss + 0x274);
arg0[4] = *(.bss + 0x278);
return;
}

こんな感じになりました。

.bss + 0x268 に何かシンボルが定義されてないか調べてみると・・・

$ readelf -a sharp_mmcsd_m.o
:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
:
[10] .bss NOBITS 00000000 009b14 000280 00 WA 0 0 4
:
Symbol table '.symtab' contains 310 entries:
Num: Value Size Type Bind Vis Ndx Name
:
136: 00000268 0 NOTYPE LOCAL DEFAULT 10 w0
137: 0000026c 0 NOTYPE LOCAL DEFAULT 10 w1
138: 00000270 0 NOTYPE LOCAL DEFAULT 10 w2
139: 00000274 0 NOTYPE LOCAL DEFAULT 10 w3
140: 00000278 0 NOTYPE LOCAL DEFAULT 10 w4

.bss (section 10) の 0x268 〜 0x278 は w0 〜 w4 として定義されているようです。

以上のシンボルを反映させて、さらに引数名をそれらしく命名すると、

void pxa_sd_get_response_value (int *resp)
{
resp[0] = w0;
resp[1] = w1;
resp[2] = w2;
resp[3] = w3;
resp[4] = w4;
return;
}

こんな感じになります。こうして処理を理解しながら改造ポイントを探っていきます。

とりあえず、今回はここまで。

リナザウでも SDHC を使いたい!

久しぶりに Amazon をのぞいてみたら非SDHCの4GSD (TS4GSDC)がついに品切れになってました。
もう手に入らないのかぁ。今となっては 2GSD じゃ物足りないしなぁ。SDHC使えるようにならないかなぁ。

Angstrom 環境(kernel-2.6)なら SDHC も使えるらしいので、純正環境(kertnel-2.4)でもドライバ次第で使えるはずなんですが、SD ドライバのソースが開示されていないので手も足も出ない状態です。

無謀にも kernel-2.6 からバックポートしようかなぁとも思ったんですが、ブロックデバイスのドライバは書いたことないし、SDHCの規格知らないし。。。
あと、うまくポーティングできたとしても、タスクトレイのアイコンと同期させるのは無理だろうし。。。
うーむ。

と、まぁ、以前からそんなことを考えてはいたのですが、ある日、SDHC のドライバを書いたことがある会社の先輩にSDHCについて何気なく聞いてみると、「SDとSDHCは初期化位しか差はないよ。あとはほとんど同じ」と言われました。

え?まじ? 初期化だけごまかせればいいってこと?
それくらいなら Binary Hack で何とかなるかも?? <- 無謀 ^^;

ということで、今月の初めくらいからtetsuさんのとこで配布されている4GSD対応SDドライバの解析を始めてみました。少しずつですが解析が進んでいるのと、ちょうど最近コメントでSDHC関係の書き込みがあったりしたので、4GSD へ ipk インストールの道シリーズのように経過を書いていこうと思います。

あ、解析の結果、ダメだったという可能性もありますので、あまり期待せず、ゆるーく見守っていただけるとありがたいです (^^;

まず、必要なものを集めます。

まずSD AssociationからSDHC の簡易仕様書がダウンロードできます。簡易仕様書ではSDHCドライバは書けないと勝手に思っていたのですが、そんなことはなく、ちゃんとすべて書いてあるようです(と前述の先輩が言ってました)。英語だからってちゃんと読んでなかったのがバレバレです。

あとは参考になりそうなのが、Angstrom の kernel 2.6 カーネルです。kernel 2.6 用ではありますが、PXA270のちゃんと動作するドライバのソースはとても貴重です。

Angstrom はカーネルだけポンと取得することができない(沢山パッチを当てて最終ツリーになる)ので、bitbake 環境を構築する必要があります。ここを参考に作業します。
カーネルツリーだけが欲しいので、最後の bitbake コマンドは以下のように linux-rp で実行します。

$ bitbake linux-rp 

とりあえず、最低限ですが、情報元は準備できました。次回からはドライバを解析していきます。