ラベル OpenBSD の投稿を表示しています。 すべての投稿を表示
ラベル OpenBSD の投稿を表示しています。 すべての投稿を表示

2009年7月2日木曜日

E-mobile H12HW

E-mobileの電話型端末H12HWを試す機会が会ったのでOpenBSDでのデータ通信を試してみた。H12HWは型番が示すようにHUAWEI社の製品で3.6MbpsのHSDPAに対応している。

結果を共有。

準備

以下のようにsys/dev/usb/usbdevsにProduct ID 0x1008を追加して、usbdevs.hとusbdevs_data.hを再生成しておく。
  • product HUAWEI Mobile 0x1008 HUAWEI Mobile
あとはsys/dev/usb/umsm.cのデバイス情報の構造体であるstruct umsm_type umsm_devs[]に
  • {{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_Mobile}, DEV_HUAWEI},
を追加してkernelをリコンパイルする。

結果

普通にumsm(4)のデバイスとして認識されて、pppdでppp接続も確立できた。

いまはopenbsdの次のリリースに向けた作業が進んでいるので、それが落ち着いた頃にopenbsdにはコミットしておく予定。


2009年5月14日木曜日

OpenBSDでSoftbank C01SWを使う

週末に海外の見知らぬ人から「(俺の)sierra wirelessのHSDPAモデムがopenbsdで使えないんだけど」というメールが届いた。ちょうど他の作業で煮詰まっていたので息抜きに何通かメールをやりとりして、OpenBSDのumsm(4)で動くパッチを作ってみた。先方曰く「ちゃんと動いた!」と報告してくれたが、手元に無いデバイスなので不安は残る。ふと思い立ってgoogleするとSoftBankモバイルのC01SWはSierra wirelessのOEM製品らしい。周りを少し見渡すと持っている人が見つかったので、実際にためしてみた。


Tru-install

C01SWはsierra wirelessの「Tru-install」という機能を搭載している。これは、他の3Gモデムでもよくある「普段はUSBマスストレージのデバイスとしてみえて、そこにデバイスドライバがはいってる。そのデバイスドライバをつかってモデムモードに切り替える」という機能だ。windows以外ではあんまり便利ではないし、自分でモードを切り替えてあげないといけない。

Tru-installのモード変更方法

もうこの手の話は何回もしているので、簡潔にモード変更方法を書いておく。
  • USB requestType = Write/Vendor/Device
  • USB request = 0x0b
  • USB request wValue, wIndex, wLength = 0x1, 0, 0
というコントロールリクエストをデバイスに送ると、デバイスがUSBバスから切り離されて再度認識されたときにはモデムデバイス+マスストレージデバイスの複合デバイスに変化している。上記に対応する関数を抜粋すると、こんな感じ。


#define TRUINSTALL_CHANGEMODE_REQUEST 0x0b
usbd_status
umsm_truinstall_changemode(usbd_device_handle dev)
{
usb_device_request_t req;
usbd_status err;
req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
req.bRequest = TRUINSTALL_CHANGEMODE_REQUEST;
USETW(req.wValue, 0x1);
USETW(req.wIndex, 0);
USETW(req.wLength, 0);

err = usbd_do_request(dev, &req, 0);
if (err)
return (EIO);
return (0);
}


umsm.cに対する変更の全体はCVSで参照できる。

あと、OpenBSDではsys/dev/usb/usbdevsにこのデバイス用のProduct IDを追加しなければならなった。これは追ってコミットしておく。

C01SW概略

アタッチしてみてちょっと驚いたのはインターフェイスが7本出現したことだ。一般に3Gモデムは複数(2−3本)のインターフェイスを用意しているが7本出てきたのは初めてだった。
USBディスクリプタを見ると4-7本目のインターフェイスはインタラプトエンドポイントを含んでいるのでこれらのどれかが通信用のポートのはずだ。上から試してみたところ、4本目が通信用のポートだった。5−7本目のポートはエコーバックされないがATコマンドに反応しているので何らかの管理ポートだと推測される(詳細は見ていない)。

C01SWで通信する

OpenBSDのkernel ppp実装のpppdを使って通信を試みたところ、さっくりとつながった。
設定は昔「NetBSDでEmobile D02HWを使う(設定編)」で書いた物とほとんど同じで、
  • ifconfig ppp0 create でpppインターフェイスを作る
  • /etc/ppp/peers/に対応する設定ファイル(たとえばsoftbank )を作ってttyU3を通信ポートに設定する
  • ソフトバンク用のユーザIDとパスワードを/etc/ppp/chap-secretに書いておく
だけだった。pppd call softbankだけでpppがつながって通信できた。


2009年5月12日火曜日

E-mobile D12HWとD22HW

E-mobileの最近のモデムを触ってみる機会があったのですこし調べてみた。結果を共有。


触ったのはD12HWD22HWで両方ともHUAWEIのOEM製品だ。D22HWはHSUPAでアップリンクが最大1.4Mbpsまで使えるというのが特徴らしい。

OpenBSDで試してみる

HUAWEIの多くのモデムは同じUSBベンダIDとプロダクトIDを共有しているが、今回もその例に漏れず同じIDを利用していた。OpenBSDで試してみたところ、両者とも標準的なHUAWEIプロトコルでUSBマスストレージモードからモデムモードに遷移するようだ。umsm(4)としてデバイスは認識される。pppd経由でネットワーク接続もできたようなので何の工夫もせずに普通につかえる。

メモ:D12HW

D12HWに関してはUSBのディスクリプタの文字列が壊れている部分がある。利用する分には問題はないがUSBディスクリプタの文字列を信用してデバイス認識時に画面に出力してしまうとなんだかよくわからない文字列が表示されてしまうかもしれない。
しょうがないのでOpenBSDではディスクリプタ中の文字列を信用せずにusbdevsの中の文字列を利用するようにUSB_QUIRKS: UQ_NO_STRINGSを設定しておいた。本来はD12HWだけでこのquirksが使われるようにすべきだがみんな同じベンダIDとプロダクトIDを持っているのでほとんど全部のHUAWEIモデムにこのquriksが適用されてしまっている。


2009年4月26日日曜日

E-mobile D21LCをOpenBSDで使う

少し前の話だがE-mobileのD21LCをしばらく借りることができたので、少し解析してOpenBSDで使えるようにしてみた。その時の話をメモとして残しておくことにする。

D21LCは中国のLongcheer社製のHSDPAモデムだ。E-mobileでは最初はHuawei社のモデムを使っていたが、しばらく前から2社の製品を投入している。D21LCも他のE-mobileのモデムと同様に「ゼロインストール」機能が搭載されている。ゼロインストールとはドライバが入っていないOS(つまり初回挿入時)にはモデムをUSBマスストレージデバイスとして認識させて必要なドライバをモデムから直接インストールさせる仕組みである。ドライバが動き始めると、そのドライバがモデムのモードを変更してモデムとして動作するようになる。Windowsなどからは大変便利な機能であるが、ほかのOSで使うためにはちょっとおせっかいだ。

Huawei社のモデムはメモ:D02HW解析で昔書いたように特別なUSBコマンドを発行すると、USBマスストレージモードからモデムモードに動作モードが切り替わった。D21LCの場合はどうだろうか?

D21LC:モデムモードへの切り替え

USBアナライザでUSBトランザクションをモニタしてみると、あるタイミングでデバイスがリセットされるタイミングがあった。これがモデムモードへの切り替えコマンドだろうと推測してもう少し中身を眺めてみる。


D21LCのモード変更コマンドはUSBマスストレージデバイスに対するコマンドとして実装されていた。(コマンドパケットの先頭の0x55 0x53 0x42 0x43:USBCが規定のマジックナンバー)といっても、USBマスストレージデバイスの仕様には定義されていない独自コマンドを発行している。
さらにモデムの動作を眺めてみたが、それ以降は普通の3Gモデムと同様の動作をしているようだ。
というわけで、このシーケンスを発行するようにデバイスドライバを拡張してやれば、ほかのOSでもモデムとして利用できるはずだ。

シリアルポート


D21LCではシリアルポートが3本生成される。モデムポートは3本目(openbsdの場合はttyU2)だった。

OpenBSDのデバイスドライバの拡張

実はすでにOpenBSDのumsm(4): 3Gモデム用デバイスドライバでは、このようなUSBマスストレージ型のモード変更デバイスを扱うための機能をすでに実装してある( umsm_umass_changemode() @umsm.c)。 似たようなデバイスを扱うために実装しておいたものだが、今回はこの関数を少し拡張して利用することにした。
すでにOpenBSDのCVSへマージされている(差分)を参照すればわかるが、上でキャプチャしたコマンドをタイミングよく発行するだけだ。
コマンド発行部分の差分を以下に載せておく。いままで2種類の同様なコマンドがあったので、3種類目として拡張しておいた。










おまけ:D21LC雑感

実際に使ったのは短い期間だったが、D21LCを使って気がついたのは、「デバイスがサポートしていないコマンドを受理するとフリーズすることがある」ということだ。正式に使えるコマンドセットが公開されているわけでもないのでバグというのは言いすぎだが、ちょっとした動作確認でハングアップしてしまうことが多くて困ることが多かった。最初はデバイスドライバ側が悪いのかと思ったが、Windowsでも同じ操作で同じ状態に陥ることが確認されたのでデバイス側に問題があるんだと思っている。

2008年5月13日火曜日

OpenBSDでEmobile D02HWを使う(1)

縁あってOpenBSDの開発者の人たちと一緒にhackする機会があったので、なにかコントリビューションできることはないかなと考えたところ、OpenBSDの3Gモデムのサポートを拡張することにした。
特にD02HWは、本当の名前はE220といって世界各地で使われているメジャーなモデムなので、これがまともに使えるようになるとうれしい人がそれなりにいるだろうから、ちょうど良い。

OpenBSDもNetBSDと同様に、FreeBSD由来のUSBサブシステムを採用しているので、usbデバイスドライバは大きな差異は存在しない。NetBSD用につくったuhmodem(4)をそのまま移植するという手もあったのだけど、OpenBSDにはHSDPAモデム用のドライバとしてumsm(4)がすでに存在していたので、それを拡張する形で実装してみることにした。

umsm(4)(拡張前)
dev/usb/umsm.c(rev.1.21)を眺めてみると、非常にシンプルなドライバになっていた。具体的に言うと、

struct ucom_methods umsm_methods = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
};

となっていた。struct ucom_methods は、上位ドライバとなるucom(4)のopen/closeなどの各処理におけるデバイス依存コードへの関数ポインタを渡すための構造体なので、この状態ではシリアルに関する処理はucomでのデフォルト動作だけで実行されることを意味している。

どうしてこれで他のドライバが動作しているのだろうか?と「???」と思いながらざっくりとコードを追ってみたところ、シリアルデバイスのinterrupt endpointに関する処理がざっくりと抜け落ちていることに気がついた。単なるin/out endpointを処理するだけなら、確かにucom(4)における特別な処理は必要ないが、モデムで通信を行う際には自分から始めるだけではなく割り込み処理が必要である。
近くにいたOpenBSD開発者に聞いてみたら「おれが使っているE220で昔だれかが作ったパッチで試した見たところ、たしかにPPPまでは張れることもあるがうまく動かなかった。つながるけど切れたり通信できなかったりしてね。それから使ってない」と言われた。さもありなん、ということでinterrupt endpointの処理を拡張するところから始めることにする。D02HW(E220)以外でも役にたつだろう。

interrupt endpoint処理の追加

endpointの割り当て処理はumsm_attach()の中で行われる。data用のbulk in/out endpointしか処理していなかった部分を、以下のように変更する。また、struct umsm_softcにもinterrupt endpoint周りの状態を保持するための変数を拡張しておく。

if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
sc->sc_intr_number = ed->bEndpointAddress;
sc->sc_isize = UGETW(ed->wMaxPacketSize);
DPRINTF(("%s: find interrupt endpoint for %s\n",
__func__, sc->sc_dev.dv_xname));
} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
uca.bulkin = ed->bEndpointAddress;
else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK)
uca.bulkout = ed->bEndpointAddress;


これで、interrupt endpointを持っているinterfaceがあったら、interrupt endpointを正しく扱うための準備ができる。

次に、ucomをopenしたときに検出したinterrupt endpointをucom割り込みとして利用するためのコードを追加しなければならない。まずucomをopenしたときにusb的にinterrupt endpointを登録するコード(usbd_open_pipe_intr()を呼ぶ)と、closeしたときに後始末(usbd_about_pipe() & usbd_close_pipe()を呼ぶ)をするデバイス依存の関数を追加する。それぞれubsa(4)から持ってきて、umsm_open(), umsm_close()ということにしておく。ucomがopen/closeされるタイミングで呼ばれるデバイス依存関数は、前述のstruct ucom_methodsで指定しておけばよい。

さらに割り込み発生時に呼び出されるデバイス依存関数とその補助関数として、同じくubsa(4)からumsm_intr(), umsm_get_status()を持ってくる。同様にstruct ucom_methodsに指定する。

これで、interrupt endpoint周りの処理は完了。普通のHSDPAモデムのDoCoMo A2502をつなげて試してPPPセッションが正しく張れるようになっていることを確認。とりあえずここまでで半分くらい終了。

ここまでのコードの差分は、OpenBSD CVSwebで確認できる。

次回のエントリーでは、D02HWのモード遷移のための関数の統合について書く予定。