ae2関連

/dev/ae2 はオーディオドライバ周りの入り口みたいなので調査してみました。
毎度の事ですが、内容は無保証ですが、間違い指摘や動作報告は歓迎いたします。

現在の状況と分かっている事

  • ドライバのモジュール化した。
  • ドライバ動作を dmesg でトレース可能にした。
  • ドライバへの入出力データを cat /dev/ae2debug で出力可能にした。
  • 音源サービスを再起動すると /dev/ae2 を初期化している。
  • オーディオ再生時に /dev/ae2 への ioctl が発生している。

現状の課題

  • ドライバへの入出力用ユーザランド側の検証プログラムが出来ていない。→着手しました。Audioユーザ側関連
  • /dev/ae2 への ioctl でやりとりされているデータの意味が分かっていない。(特にreadとwriteでのデータ)
  • /dev/audio_dev_ctrl の入出力の調査不足。
  • 音源チップの仕様が全く分からない。


ドライバをkernelモジュールにする

kernel/drivers/yamaha/Makefile
obj-y から obj-m に変更
#obj-y := ae2drv.o
obj-m := ae2drv.o
kernel の make が完了すると、
kernel/drivers/yamaha/ae2drv.ko
ができるので実機に転送、
$ adb  push ae2drv.ko /system/lib/modules/
init.rcを編集して起動時にinsmodするようにする
insmod /system/lib/modules/ae2drv.ko
ae2drvを抜いたkernelと編集したinit.rcでboot.imgを作成し、ubi化して実機に転送し、recoveryエリアに書き込む。
リブートして完了

recovery領域の書き換え回数が減る事、driver のコード変更を再起動無しに試す事が出来る。

ドライバの入出力をトレース可能にする

wikiに貼り付けると大量になるので github にすべてをアップしている。
私自身がkernel側コードは素人の為、大量の日本語コメントとprintkを追加している。
また、リードとライト部分は似たような動作を2重に行っていて、実入出力とトレース書き出しを分けている。
( #if で大量になるのが嫌だったためと、実転送部分とトレース記録を分けたかったため。 )
間違いがあれば、Twitterかコメント欄にてお知らせ頂けると幸いです。
https://github.com/is01rebuild/is01_kernel_2_6_29_debug
更新情報:20110227_02 bug fix
ドライバのソースコードは ae2drv.c です。上記リンクからもたどれますが、面倒なので直リンク張っておきます。
https://github.com/is01rebuild/is01_kernel_2_6_29_debug/blob/master/drivers/yamaha/ae2drv.c
これを、上記の「ドライバをkernelモジュールにする」のdriver部分を置き換える。
(リネームして別名のkernelモジュールにした方が切り替えが出来て良いと思われる)
github に上げたドライバはトレース可能にしたもののエラー処理を所々省いているため、長時間運用はできないので注意の事。

ドライバの rmmod、insmod・サービス再起動方法

init.rc にて insmod すると起動直後から音が鳴るようになるが、このままでは rmmod できない。
rmmod するにはサービスの停止をしてから行う。
下記例はrooter を入れて on にしているか、busybox がインストールされている状態が前提になっている。
rmmod
$ adb shell
# stop mediayamaha
# kill -9  `ps | grep mediayamaha | awk '{print $2}'`
# rmmod ae2drv
insmod
# insmod /system/lib/modules/ae2drv.ko
dmesg で insmod 時のモジュール初期化時における、kernelでのメモリ確保状態を出すようにしている。
# dmesg
dmesg のバッファをクリアする場合は dmesg -c を実行。
/devに追加されたかどうか確認
# ls -l /dev/ae2*
# crw-rw-rw- system   audio    229,   0 2011-02-25 01:42 ae2
# crw------- root     root     229,   1 2011-02-25 01:42 ae2debug
メジャー番号である229は実行環境によって異なるかもしれない。
dmesg すると ae2drv.ko のデバッグ情報や動作中のデバッグ情報もかなり出しているので、dmesg 出力結果がうるさい場合は適宜ドライバコードの該当部分をコメントアウトして欲しい。
サービスの起動、mediaserver 再起動
# start mediayamaha
# kill -9  `ps | grep mediaserver | awk '{print $2}'`

/dev/ae2のパーミッションと所有者情報は何処で指定されているのか追いかけていないため不明。。。

debugドライバの使い方

PC にてTerminalをもう一つ開いて
$ adb shell cat /dev/ae2debug > ae2debug.txt
等とすると、 ae2debug.txt にトレース結果がでる。
/dev/ae2debug への書き込みには未だ対応していない。
何か書き込みが来たら、内部バッファをクリアさせる予定。だが、実装するかどうかは今後の進捗による。
先に、ユーザランド側を書いてみて、うまくいかなかったら実装する必要が出てくるかも。

現状、このトレース結果の妥当性検証は済んでいないため誤りがあるかもしれない。
出力結果をc言語コードに簡単に取り込めるように出力するようにした。。が、まだ未検証。

結果の最後に総数を出力している。
この数はinsmodして、start mediayamaha、mediaserver を再起動した直後の結果。これも、膨大な量の為、まだ未検証。
ReadWriteCount.allCount=5726;
ReadWriteCount.waitCount=77;
ReadWriteCount.sleepCount=202;
ReadWriteCount.writeCount=3157;
ReadWriteCount.writeByteCount=2439;
ReadWriteCount.writeWordCount=20476; // 2バイト単位でのカウント ×2 でバイト数になる。
ReadWriteCount.readCount=893;
ReadWriteCount.readByteCount=893;
ReadWriteCount.readWordCount=0;
ReadWriteCount.disableCount=697;
ReadWriteCount.enableCount=697;
ReadWriteCount.resetCount=1;
ReadWriteCount.waitIRQCount=1;
ReadWriteCount.cancelCount=0;
ReadWriteCount.setCount=1;

ドライバからのdebug情報

・サービス初期化完了段階
 dump[4562] 付近
・mediaserver 再起動完了
 dump[5727] 付近
・画面タップ音をカーソルキー操作で発音完了直後
 dump[9450] 付近
・発音完了して、GPIOがOFFになった頃
 dump[9838] 付近

ioctlによる、driverからチップへのreadとwrite(?)

2ch root4 スレッドにて、452氏より、最初のwriteWord[0]~の24KBほどのデータは
/system/lib/libmediayamahasmw.so の
0007C954 : 2D 61 AE AE 2D 61 2D 61 2D 61 2D 61
~ 
と一致すると報告された。

上記 cat /dev/ae2debug の出力結果から大量のデータがチップに転送されている。が、その内容の多くは現在不明。
/system/etc/yamaha/effect/param
/system/lib/
この2つのディレクトリ以下にあるデータと付き合わせてみる必要が有るかもしれない。これもデータが大量。

初期か段階での読み込みは1バイト単位のみ、結果の確認のみだろうか?

リードとライトのフォーマットはdriverの
kernel/drivers/yamaha/madrv.h
に構造体として宣言されている。
struct ma_IoCtlWriteRegWait
{
	unsigned long	dAddress;		/* I/F Address */
	const void	*pData;		        /* Write Pointer */
	unsigned int	dSize;			/* Write Size(data type size) */
	unsigned int	dDataLen;		/* Data Length */
	unsigned int	dWait;			/* Wait ns */
};

struct ma_IoCtlReadRegWait
{
	unsigned long	dAddress;		/* I/F Address */
	void		*pData;		        /* Read Data Store Pointer*/
	unsigned int	dSize;			/* Read Size(data type size) */
	unsigned int	dDataLen;		/* Data Length */
	unsigned int	dWait;			/* Wait ns */
};
で、問題は I/F Address が何を意味する(何かのregisterアドレスかな??)のか分からない。
Write Pointer はユーザランド側のデータへのポインタである。
driver内でユーザ領域からkernel領域にデータがコピーされた後、ioremapアドレス+I/F Addressで読み書きされている。
実例は cat /dev/ae2debug をして確認してみてほしい。

ioctl のコマンド

#define MA_IOC_MAGIC 			'x'
#define MA_IOCTL_WAIT 			_IOW( MA_IOC_MAGIC,  0, unsigned int )
#define MA_IOCTL_SLEEP 		_IOW( MA_IOC_MAGIC,  1, unsigned int )
#define MA_IOCTL_WRITE_REG_WAIT         _IOW( MA_IOC_MAGIC,  2, struct ma_IoCtlWriteRegWait )
#define MA_IOCTL_READ_REG_WAIT 	_IOWR( MA_IOC_MAGIC, 3, struct ma_IoCtlReadRegWait )
#define MA_IOCTL_DISABLE_IRQ 		_IO( MA_IOC_MAGIC,   4 )
#define MA_IOCTL_ENABLE_IRQ 		_IO( MA_IOC_MAGIC,   5 )
#define MA_IOCTL_RESET_IRQ_MASK_COUNT	_IO( MA_IOC_MAGIC,   6 )
#define MA_IOCTL_WAIT_IRQ 		_IOR( MA_IOC_MAGIC,  7, int )
#define MA_IOCTL_CANCEL_WAIT_IRQ 	_IO( MA_IOC_MAGIC,   8 )
#define MA_IOCTL_SET_GPIO 		_IOW( MA_IOC_MAGIC, 9, unsigned int )

間違いが多く含まれているかもしれません、何かお気づきの点が有りましたら、Twitterか下記まで。
コメント
名前:
コメント:

すべてのコメントを見る




(2011/02/25 2:12 初版公開)
最終更新:2011年03月07日 20:11
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。