2007年12月26日水曜日

PSOC miniprog用コネクタ

PSOCをつかった回路をつくるときに、miniprogとの接続をどうしようか?っていうのはちょっとだけ悩ましい。普通の5pinのシングルラインのヘッダピンでも用は足りるけれど差し込みが安定しないし、ぼーっとしていると逆差ししてしまうかもしれない。Cypressが指定している純正の受け側のコネクタが手に入れば良いのだが秋葉原をちょっと回った感じでは難しそう。

最近気に入っているのは、molexのこのコネクタ。秋葉原の「ネジの西川」こと西川電子部品の2階のコネクタ売り場で探しているときに見つけたのだが、純正のコネクタとだいぶ近い形をしている。
型番は

  • Molex 5045-05A (ストレート)
  • Molex 5046-05A (L字)
とのこと。

このままでは右の写真のようにロック部分が長くてMiniprogと干渉してしまうのだが、


適当に切断すると


ぴたりとはまるようになる。

というわけで、秋葉原にアクセスできる人はこーいう方法もある、ということで。写真ではストレートコネクタを例につかったが、L字型のほうが使うことは多いかな。

NetBSDでEmobile D02HWを使う(設定編)

NetBSDのpppdのemobileにつなげる方法を教えてもらったので設定してみた。設定をまとめておく。
(まだ最適化はされていないので冗長な記述などがあるかもしれない)

設定するファイルは以下の5つ

  • /etc/ppp/peers/emobile
  • /etc/ppp/chat-emobile
  • /etc/ppp/ip-up
  • /etc/ppp/ip-down
  • /etc/ppp/chap-secret
これらを設定して、ppp call emobile を実行すればいい感じにPPPセッションが確立してくれる。

/etc/ppp/peers/emobile

dtyU0 460800 crtscts
lock
nodetach
hide-password
local
noauth
# dns routing
usepeerdns
defaultroute
noipdefault
# disable compressions
novj
noccp
nobsdcomp
# auth
user "em"
# misc? (xxx)
ipcp-restart 8
ipcp-max-configure 50
ipcp-accept-local
ipcp-accept-remote
# connect script
connect '/usr/sbin/chat -v -f /etc/ppp/chat-emobile -T *99***1#'


/etc/ppp/chat-emobile

ABORT "NO CARRIER"
ABORT "NO DIALTONE"
ABORT "ERROR"
ABORT "NO ANSWER"
ABORT "BUSY"
ECHO ON
SAY "Connecting"
TIMEOUT 15
"" "\d\d\dat\r\dat"
TIMEOUT 5
"OK-\Kat-OK" "at"
OK "at&FE1V1X1&D2&C1S0=0"
OK "at+ipr=230400"
SAY "Let's go"
OK "atdt\T"
CONNECT ''


/etc/ppp/ip-up (chmod 0755 /etc/ppp/ip-upしておくこと)

#!/bin/sh
~
f [ -f /etc/ppp/resolv.conf ]; then
chmod 644 /etc/ppp/resolv.conf
cp /etc/resolv.conf /etc/resolv.conf-
if [ ${USEPEERDNS:-0} -eq 1 ]; then
cp /etc/ppp/resolv.conf /etc/resolv.conf
chmod 644 /etc/resolv.conf
fi
fi


/etc/ppp/ip-down (chmod 0755 /etc/ppp/ip-downしておくこと)

#!/bin/sh
#
if [ -f /etc/resolv.conf- -a ${USEPEERDNS:-0} -eq 1 ]; then
mv /etc/resolv.conf /etc/resolv.conf.old
cp /etc/resolv.conf- /etc/resolv.conf
chmod 644 /etc/resolv.conf
fi

if [ -f /etc/ppp/resolv.conf ]; then
mv /etc/ppp/resolv.conf /etc/ppp/resolv.conf-
fi


/etc/ppp/chap-secret (chmod 0600 /etc/ppp/chap-secretしておくこと)

em * em

USBアナライザとD02HW

「NetBSDでD02HWをつかう」では比較的(というかほぼ全部)試行錯誤でデバイスの設定に必要な条件を推測してデバイスドライバへのパッチを作成した。ハードウェアを触るときによく感じることは「見えないものはわからない」ということだ。当たり前のことだが、電気信号は眼にはみえないので、推測するしかなくそれはいつまでも推測のままで推移してしまう。電圧を測るのにテスターが必要で、時間ドメインの波形をみるのにオシロスコープが必要なように、扱う事象を見るための専用の「アナライザ」が必要になることは多い。実はとある目的のためにUSBバスアナライザが手元にあったので、D02HWのデバイスドライバ作成作業を検証してみることにした。

手元にあるのはellisysUSB Explorer 200だ。これは、USB2.0のHighSpeed(480Mbps)に対応したアナライザで、Windowsソフトウェアと組み合わせることでだいたいすべてのUSBイベントを表示してくれる、という便利な逸品である。ソフトウェアは誰でもダウンロードできるようになっていて、USBバスのキャプチャファイルを入手したときに誰でも表示できるのがうれしい(ちなみにキャプチャファイルの拡張子はUFOだ)。
写真でわかるように、アナライザを解析ソフトが入っているPCにつなげて、デバイスとデバイスをつなげるホストの間にはさむようにアナライザを配置する。これで、デバイスとホスト間のデータをインターセプトするという仕組みになっている。
まず、Windowsで動かしてみたときにUSBバスにどんなトランザクションが発生しているかを見てみた。
NetBSDでEmobile D02HWを使う(3)」にあるUSBのインターフェイスとエンドポイントの情報を見ながら、どのエンドポイントとホストがどんな通信をしているかを眺めてみる。アナライザは、

たとえばこんな情報が表示されて、トランザクションのタイプと中身のデコード結果をだしてくれるので、それとUSB2.0の仕様書(このへんにある)を眺めながら追っていく。赤裸々にどんなトランザクションをやりとりしているかを見ていてわかったことは以下の3つ。

  • NetBSDにつくったパッチは正しい。
  • ATコマンドいろいろ
  • D02HWは実はさらに別のインターフェイスをもっている。
最初のは、結局あのシーケンスを送らないとデバイスは言うことをきいてくれないみたいだ、ということを追認できたということだ。ちゃんとUSB2.0の仕様書を読み込むと、あのメッセージは
  • デバイスへのスタンダードのリクエスト(SET_FEATURE)でHost→Device
  • リクエストタイプはDEVICE_REMOTE_WAKEUP
  • wIndexの0x2はendpoint2を意味する
ということだった。アナライザでの結果をみるとendpoint2はモデムの主通信用のパイプなので、これで意味がわかってすっきりした。
2つめのATコマンドいろいろはたぶんWindowsとかのモデム定義ファイルをみればわかる情報なので大した追加情報ではない。問題は3つめで、確かに「NetBSDでEmobile D02HWを使う(3)」では、モデムとして認識されるようになると3つのインターフェイスディスクリプタが見えている。ひとつはモデムでひとつはUSBストレージデバイスだ、ということもわかっていたが、実はなぜもうひとつみえるのか、は謎のまま残っていた。まだ実際にコードを書いて叩いてみたわけではないのだが、USBのBUSトランザクションを見る限り、

INTERFACE descriptor 1:
bLength=9 bDescriptorType=interface(4) bInterfaceNumber=1 bAlternateSetting=0
bNumEndpoints=2 bInterfaceClass=255 bInterfaceSubClass=255
bInterfaceProtocol=255 iInterface=3(Data Interface)

ENDPOINT descriptor:
bLength=7 bDescriptorType=endpoint(5) bEndpointAddress=5-in
bmAttributes=bulk wMaxPacketSize=64 bInterval=0

ENDPOINT descriptor:
bLength=7 bDescriptorType=endpoint(5) bEndpointAddress=5-out
bmAttributes=bulk wMaxPacketSize=64 bInterval=0

のendpoint5はもう一本のモデム制御用のパイプらしい。まだ憶測だが、endpoint2でデータ通信しながらでもモデムが管理しているHSDPA由来の制御情報などを並列してとれるのではないかと予想している。これを扱うデバイスドライバかくのはどうしたもんか、と悩みがふえてしまった(しばらくはきっとやらないけどね)。

(12/28追記:実験してみたらモデムモードに入った後は3本ともシリアルらしい。2本目をはやすハックをしてみた、あとで詳しく書く予定)
(12/30追記:やっぱり3本目はusb mass strageだとおもうなあ。コードかいてみるか。。)
(1/4追記:usb mass strageでした。)

というわけで、アナライザを使うとみたいことも見えるけど、まったく気が付いていなかったようなことも見えてしまう、ってことで。今回はおしまい。

2007年12月25日火曜日

NetBSDでEmobile D02HWを使う(4)

Windowsやmacのドライバでは抜き差しせずとも使えるということは、なんらかの方法でこの2つのモードの切り替えができるはずだ。機能の切り替え、はデバイス毎の特有の操作なので一般的な方法は存在しない。USBのバスアナライザとかがあれば、windowsのドライバの挙動などを観察して切り替えるための魔法の言葉を見つけることもできるのだが、休日に家で作業をしていたので手元にそんな便利なものはなかった。
というわけでいろいろと試行錯誤してみることにする。

  • 試行1:D02HW(E220)のファームウェアの立ち上がりが遅くてうまく処理ができていないのでは無いかと思って、attachルーチンのあちこちにdelayを入れてみる。あちこちにusbd_delay_ms(dev, 500); などと書いてみて、挙動がどう変わるか地道な作業をがんばる(2時間くらい)。


/* Find the endpoints */
usbd_delay_ms(dev, 2000);
id = usbd_get_interface_descriptor(sc->sc_iface);
sc->sc_iface_number = id->bInterfaceNumber;

あたりに2000msくらいのdelayをいれると、認識しない→差し直すと認識→次に刺し直すと認識しない→また差し直すと認識、と安定してツンとデレを繰り返すようになった。しかしディレイを入れるだけではどうもこれ以上は進まないようだ。次の方法を考えないといけない、ネットワークで識者(USBシリアルの偉い人)と相談するととりあえずVENDORリクエストなどで適当な値をおくってデバイスをつつくかくすぐるかしてやるのがいい、と助言をうけた。設計している人も人の子なので別に難しい値ではなく0とか1とか2とかそんな値を送ると動き出すことがあるらしい。

というわけで、sys/dev/usb/uplcom.cを参考にして実験用にubsa_reset()という関数をでっちあげてみた。


static usbd_status
ubsa_reset(struct ubsa_softc *sc)
{
usb_device_request_t req;
usbd_status err;
#define UBSA_SET_REQUEST 0x1

req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
req.bRequest = UBSA_SET_REQUEST;
USETW(req.wValue, 0);
USETW(req.wIndex, sc->sc_iface_number);
USETW(req.wLength, 0);

err = usbd_do_request(sc->sc_udev, &req, 0);
if (err) {
printf("%s: send reset fail\n", __func__);
return (EIO);
}

return (0);
}


  • 試行2: ubsa_reset()関数をattachの適当な場所においてみて挙動を見る。が、デバイスからお断りのエラーが返ってくるのでどうもうまくいかないらしい。
  • 試行3: bmRequestType を UT_WRITE_DEVICEにしてbRequest = UR_SET_FEATUREにしてやってみることにする。これはUSBの標準機能なので失敗することはないはず。コードは適当に改変する。
ここで変化が起こった。なんとリクエストを送りつけると、抜き差ししてもモードの変換が発生せずに常にモデムとして見えない状態になる。「逆行してるじゃん」と思うのは素人だ。なにかアクションが返ってきたと言うことは、その近くに正解が隠れている可能性が高い。試行錯誤を繰り返して問題を追い込んでいくことにする。ここまで7時間近く作業をしていてどうもだれぎみだったのが、ちょっとテンションがあがってきた記憶がある。脳内麻薬でもでていたんじゃないかな。しばらくするとリクエストのwIndexの値を0x2にすると、デバイス側がUSBリセットをかけてきて一度デタッチされ、再度OSがアタッチするときにはモデムに化けている、という挙動をするということが判明。ようやくつねにデレにするマジックワードをゲットできた。

あとはコードをまとめるだけだが、最終的には、

/*
* Hauwei E220 needs special request to enable modem function
* XXX: is there more smart methods?
*/
Static usbd_status
ubsa_e220_modechange_request(struct ubsa_softc *sc)
{
#define UBSA_E220_MODE_CHANGE_REQUEST 0x2
usb_device_request_t req;
usbd_status err;

req.bmRequestType = UT_WRITE_DEVICE;
req.bRequest = UR_SET_FEATURE;
USETW(req.wValue, 0x1);
USETW(req.wIndex, UBSA_E220_MODE_CHANGE_REQUEST);
USETW(req.wLength, 0);

DPRINTF(("%s: send e220 mode change request\n", __func__));
err = usbd_do_request(sc->sc_udev, &req, 0);
if (err) {
DPRINTF(("%s: E220 mode change fail\n", __func__));
return (EIO);
}

return (0);
#undef UBSA_E220_MODE_CHANGE_REQUEST
}

みたいな呼び出しをUBSA_ATTACH()の中で

/* Find the endpoints */
/* Hauwei E220 need special request to change its mode to modem */
if (sc->sc_devtype_e220) {
err = ubsa_e220_modechange_request(sc);
if (err) {
printf("%s: failed to change mode: %s\n",
devname, usbd_errstr(err));
sc->sc_dying = 1;
goto error;
}
}

id = usbd_get_interface_descriptor(sc->sc_iface);
sc->sc_iface_number = id->bInterfaceNumber;

こんなふうに呼び出す実装にしてみた。このカーネルでは、


ubsa0 at uhub0 port 2
ubsa0: HUAWEI Technologies HUAWEI Mobile, rev 1.10/0.00, addr 2
ubsa0: HUAWEI E220 need to re-attach to enable modem function
ubsa0: at uhub0 port 2 (addr 2) disconnected
ubsa0 detached
ubsa0 at uhub0 port 2
ubsa0: HUAWEI Technologies HUAWEI Mobile, rev 1.10/0.00, addr 2
ucom0 at ubsa0

みたいに自動的にucom0がアタッチされるようになる。いったんdettachされるのが美しいか?みたいな議論をするともめそうだけど、デバイスの仕様ってことで許してくれないかなーとコッソリ期待している。

tipでucom0につなげてみると、こんな感じにみえる。userland-PPPでemにもつながったので、たぶんこれでサポートのためのハックは完了。実はまだNetBSDのkernel ppp(pppd)の設定がうまくいかないので、設定方法を教えてくれる人も募集中。


#tip dtyU0
connected
at
OK
atI
Manufacturer: huawei
Model: D02HW
Revision: 11.005.08.00.168
IMEI: 3560600XXXXXXXX
+GCAP: +CGSM,+DS,+ES

OK


というわけで、D02HWを動かせるようになるまでに実際にどんな作業をしたかを書いてみた。この手の情報はできた後のコード解説程度が多いが、作業をした過程とか、どんな事を考えて作業したかとか、どんな失敗をしたか、って情報の方が、自分で同じような作業をするときに役に立つ気がしている。
あと、半年たつと自分でも何やったのか忘れることがあるので備忘録にもなることを期待しながら、できる限りこんな感じの作業記録をとってみたいなあーと考えている。

2007年12月24日月曜日

NetBSDでEmobile D02HWを使う(3)

インスタントに「NetBSDでイーモバイルを使う方法」が書いてあるかというとそうでもなくて残念だと思う人もいるかもしれない。今回書いたpatchはすでにNetBSDには送ってあるのだがこれが採用されるかどうかはまだ不明なので、最近の-currentをCVSチェックアウトしただけでは現状では使えない。今回も「どうやってUSBデバイスを動かすようにしたか」というネタが続いているのでその辺に興味があるならおつきあい頂きたい。


現状のubsaドライバではどうもうまくD02HW(E220)をアタッチできないので、もう少し先人達の知恵を借りることにした。FreeBSD系のメーリングリストを眺めるとこんな記述があった:「いったん接続して認識に失敗してから、ゆっくりとUSBコネクタを引き抜いてデタッチされた瞬間にもう一度指し直せば認識する(かも)」(意訳)、最初みたときは何のおまじないかと思っていたのだが、再度好意的に解釈し直すと「電気的な接続を切らずに信号線だけ切りはなして再接続するといんじゃない?」と言っているようにも思える。というわけでやってみた。数回トライすると、本当に認識してucom0が生えてきた。なんで?と思うとこの状態ではさっきまで見えなかったエンドポイントが複数見えるようになっており、その中にインタラプトエンドポイントが含まれている。

usbctlというコマンドでUSBのデバイスの情報を取得してみると、差し直しの前後で全然別物のデバイスになってしまったようにみえる。長いけど抜粋してみるとこんな感じ。

元々の情報


DEVICE addr 2
DEVICE descriptor:
bLength=18 bDescriptorType=device(1) bcdUSB=1.10 bDeviceClass=0 bDeviceSubClass=
0
bDeviceProtocol=0 bMaxPacketSize=64 idVendor=0x12d1 idProduct=0x1003 bcdDevice=0
iManufacturer=1(HUAWEI Technologies) iProduct=2(HUAWEI Mobile) iSerialNumber=0()
bNumConfigurations=1

CONFIGURATION descriptor 0:
bLength=9 bDescriptorType=config(2) wTotalLength=32 bNumInterface=1
bConfigurationValue=1 iConfiguration=0() bmAttributes=a0 bMaxPower=500 mA

INTERFACE descriptor 0:
bLength=9 bDescriptorType=interface(4) bInterfaceNumber=0 bAlternateSetting=0
bNumEndpoints=2 bInterfaceClass=8 bInterfaceSubClass=6
bInterfaceProtocol=80 iInterface=0()

ENDPOINT descriptor:
bLength=7 bDescriptorType=endpoint(5) bEndpointAddress=3-in
bmAttributes=bulk wMaxPacketSize=64 bInterval=0

ENDPOINT descriptor:
bLength=7 bDescriptorType=endpoint(5) bEndpointAddress=4-out
bmAttributes=bulk wMaxPacketSize=64 bInterval=0

current configuration 1

差しなおした後の情報


DEVICE addr 2
DEVICE descriptor:
bLength=18 bDescriptorType=device(1) bcdUSB=1.10 bDeviceClass=0 bDeviceSubClass=
0
bDeviceProtocol=0 bMaxPacketSize=64 idVendor=0x12d1 idProduct=0x1003 bcdDevice=0
iManufacturer=1(HUAWEI Technologies) iProduct=2(HUAWEI Mobile) iSerialNumber=0()
bNumConfigurations=1

CONFIGURATION descriptor 0:
bLength=9 bDescriptorType=config(2) wTotalLength=85 bNumInterface=3
bConfigurationValue=1 iConfiguration=0() bmAttributes=a0 bMaxPower=500 mA

INTERFACE descriptor 0:
bLength=9 bDescriptorType=interface(4) bInterfaceNumber=0 bAlternateSetting=0
bNumEndpoints=3 bInterfaceClass=255 bInterfaceSubClass=255
bInterfaceProtocol=255 iInterface=3(Data Interface)

ENDPOINT descriptor:
bLength=7 bDescriptorType=endpoint(5) bEndpointAddress=1-in
bmAttributes=interrupt wMaxPacketSize=16 bInterval=128

ENDPOINT descriptor:
bLength=7 bDescriptorType=endpoint(5) bEndpointAddress=2-in
bmAttributes=bulk wMaxPacketSize=64 bInterval=0

ENDPOINT descriptor:
bLength=7 bDescriptorType=endpoint(5) bEndpointAddress=2-out
bmAttributes=bulk wMaxPacketSize=64 bInterval=0

INTERFACE descriptor 1:
bLength=9 bDescriptorType=interface(4) bInterfaceNumber=1 bAlternateSetting=0
bNumEndpoints=2 bInterfaceClass=255 bInterfaceSubClass=255
bInterfaceProtocol=255 iInterface=3(Data Interface)

ENDPOINT descriptor:
bLength=7 bDescriptorType=endpoint(5) bEndpointAddress=5-in
bmAttributes=bulk wMaxPacketSize=64 bInterval=0

ENDPOINT descriptor:
bLength=7 bDescriptorType=endpoint(5) bEndpointAddress=5-out
bmAttributes=bulk wMaxPacketSize=64 bInterval=0

INTERFACE descriptor 2:
bLength=9 bDescriptorType=interface(4) bInterfaceNumber=2 bAlternateSetting=0
bNumEndpoints=2 bInterfaceClass=8 bInterfaceSubClass=6
bInterfaceProtocol=80 iInterface=0()

ENDPOINT descriptor:
bLength=7 bDescriptorType=endpoint(5) bEndpointAddress=3-in
bmAttributes=bulk wMaxPacketSize=64 bInterval=0

ENDPOINT descriptor:
bLength=7 bDescriptorType=endpoint(5) bEndpointAddress=4-out
bmAttributes=bulk wMaxPacketSize=64 bInterval=0

current configuration 1


つまり、差しなおしたあとのデバイスには元々見えなかったインターフェイスが生成されていて、それがみえると今回の目的であるモデムとして利用できるようになる、ということらしい。裏技みたいな「ゆっくりやさしくぬいて、素早くさす」みたいなことを何回もやるのは大変なので、USBのプロトコル的にうまくできないか?という方針のまま作業をすすめていくことにする。

続く

NetBSDでEmobile D02HWを使う(2)

CS5536を扱った時は十分に詳しい仕様書が入手できて先がみえる作業(つまり作ればできる)だったが、今回のD02HW(E220)に関しては外部の仕様書が存在しないため、いろいろと試行錯誤が必要となる。幸いにも、「ごにょごにょすると動く」とか「不十分だけど動くかも」といった情報があるし、Linuxでは動いているらしいのであまり深刻にならずにやってみることにしよう(ま、楽しみでやっているわけだし)。
前回のエントリでも出したが、この段階では接続するとこんなメッセージがkernelから出力される。

ubsa0 at uhub0 port 2
ubsa0: HUAWEI Technologies HUAWEI Mobile, rev 1.10/0.00, addr 2
usbd_set_config_index: illegal index
ubsa0: failed to set configuration: INVAL

問題となっている部分として目につくのが"usbd_set_condig_index: illegal index"の部分だ。ベースとなるsys/dev/usb/ubsa.cを開くと、その部分はUSB_ATTACH(ubsa)の中のこんなコードだった。

/* Move the device into the configured state. */
err = usbd_set_config_index(dev, UBSA_CONFIG_INDEX, 1);
if (err) {
printf("%s: failed to set configuration: %s\n",
devname, usbd_errstr(err));
sc->sc_dying = 1;
goto error;
}

usbd_set_config_index()の実体はsys/deb/usb/usb_subr.cにあるので見てみると、USBのデバイス的に「そんなINDEXはないよ」ということを意味している。ここでデバイスに頑張れといっても無い袖を振ってくれるわけでもないので、ここはUBSA_CONFIG_INDEXの値があっていないのだろうと考えるのが正しそう。もともとの値は1だったので、とりあえず0にしたkernelを作って試してみる。

すると別のメッセージが出るようになる。ubsa.cをみると、それなりにコードの先のほうまで進んでいるようだ。

ubsa0 at uhub1 port 2
ubsa0: HUAWEI Technologies HUAWEI Mobile, rev 1.10/0.00, addr 2
ubsa0: Could not find interrupt in

該当部分のコードは、さっきと同じUSB_ATTACH(ubsa)の中の、

if (sc->sc_intr_number == -1) {
printf("%s: Could not find interrupt in\n", devname);
sc->sc_dying = 1;
goto error;
}

である。ちょっと前の方にもどって追ってみると、USBデバイス(D02HW)からエンドポイントを取得してみたけど必要な割り込み用のエンドポイントをもらえなかった、のであきらめちゃう、ということらしい。割り込み用のエンドポイントがもらえないのは一大事なのでデバイスドライバとしてはあきらめるのは当然だとは思うが、動かしたい人としてはそれでは困る。
可能性としては、

  • このデバイスは割り込みエンドポイントがない変なシリアルデバイスである
  • 本来は割り込みポイントがあるが何らかの問題で見えていない
のどちらかだが、「ガシガシさしなおしていたら見えたことがある」とかいうWebなどでの報告を信じる限り、どちらかというと後者の可能性が高い。もし前者だったとしたらシリアル通信のドライバとして全然別のロジックが必要になるから偶然で動くなんて考えづらいからだ。つまり、
  • 残りのコードはおおむねあっていて、うまくデバイスとしてコンフィグレーションできていない
じゃないかと予測して次のステップに進むことにした。

続く

2007年12月22日土曜日

NetBSDでEmobile D02HWを使う(1)

イーモバイルD02HWが手元に来たので、NetBSDで動かせるようにしてみた。今回はそのあたりの話を書いてみることにする。
D02HWはD01HWとほとんど同じハードウェアで、HUAWEIE220のOEM製品である。今回も手をつける前にとりあえずgoogleとかしてみると、動いたとか動かないとかどうも歯切れがわるい。NetBSDの場合ではcurrent-usersという最新版の開発ブランチのkernelに関する話題を扱うメーリングリストがあるのだが、いくつかのスレッドがあった割には実際のコードには反映されていない状態だった。
まあ、手元に実際のデバイスがあるから、と手をつけてみることにした。

D02HWはUSBのHSDPAモデムだが、モデムの機能の前にデフォルトではUSBストレージデバイスとして認識されるようになっている。たとえば、なんの設定もしていないNetBSDではumassデバイスとして認識・アタッチされて、CDROMとして中身をmountできるようになる。中身はwindows用のデバイスドライバ群で、NetBSDでモデムとして使おうとして思っているときには何の役にもたたない。差し込みのたびにumassとして認識されるのもうるさかったので、まずそのへんをdisableする。umassのdevice driverはsys/dev/usb/umass.cあたりにある。中身をざっと見てみると特定のデバイス毎の特別な設定を書くためのhookが用意されていて、sys/dev/usb/umass_quirks.cに追加できるようになっている。今回は単純にattachされないようにするだけなので、Static const struct umass_quirk umass_quirks[] = {の中に

{ { USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E220 },
0, 0, 0, 0, 0, NULL, NULL
},

というエントリーを追加した。これで、USBのベンダIDがHUAWEIでプロダクトIDがE220のデバイスはUSBストレージデバイスとして認識されなくなる。NetBSDでは、専用のドライバが存在しないデバイスはugen(汎用USBデバイス)としてattachされるので、umassをdisableすると次からはD02HW(E220)はugenとして認識されるようになる。

このあたりでugenとして認識されたD02HWをユーザーランドからlibusbをつかってなんか操作できないかと、数時間時間を費やしてみたが、得たものは

  • NetBSDのlibusbはugenとして認識されたデバイスしか触れないということを認識
  • libusbを使った基本的なプログラムの書き方と経験
だけで、今回のデバイスドライバつくりに特に役に立つことは(その時点では)なかった。今思えば、あの段階でうまくugen&libusbを使うことで不明なUSBのコマンドを探すような場合に役にたつかも、と思えるようになったので、まあ費やした時間は無駄ではなかった(ことにした)。

と、ここからが本題となる。まずは先人達が到達したところまで追い付かなければならない。ベースとなっているUSBシリアルドライバはubsaドライバ(sys/dev/usb/ubsa.c)なので、このドライバがD02HWのドライバとなるように、Static const struct usb_devno ubsa_devs[] = {


/* HUAWEI E220 / Emobile D0[12]HW */
{ USB_VENDOR_HUAWEI, USB_PRODUCT_HUAWEI_E220 }

と追加する。この段階でkernelをつくってD02HWを接続すると

ubsa0 at uhub0 port 2
ubsa0: HUAWEI Technologies HUAWEI Mobile, rev 1.10/0.00, addr 2
usbd_set_config_index: illegal index
ubsa0: failed to set configuration: INVAL

と表示される。確かに問題がある、というところで概ねこのデバイスを触る準備が整った気になる。ちょっと一休み。

具体的な料理の方法は次のエントリーで説明する予定。