カーナビ作るぜ!(1)-2 USBGPS2をLinuxで使う(続き)

時間がそれなりにたっていて、今はそれなりに動いているのですが、ページ更新が追い付いていない今日この頃。usbgps2周りで変えたことがあったので、忘れないうちに書いておこうかと。

fedora9では、USBデバイスの認識にhotplugを使わなくなっていて、udevで処理するようになっています。最初、それがわからなかったので、hotplugを持ってきていれていたのですが、これのせいで起動時間がかなり長くなっていることが判明。udevを使うようにしてみました。

エンジンをかけてからデスクトップが表示されて使えるようになるまでが、1分40秒くらい。まぁ、通常のデスクトップLInuxとしてはそれなりに速いのではないかと思うのですが、ちと遅い。いろいろチューニング(不要なサービスをあげないだとか)してようやくこの時間。CPUの性能やメモリ、ディスク(一応SSD)周りの限界かなぁなどとも思っていたのですが、いろいろ試していたら、hotplugを切ると30秒以上短縮できることが判明。やはりどっかから持ってきて無理矢理いれているのがまずいのかなぁと思った次第です。まぁ、USBメモリはhotplug入れないでも認識していたわけで、USBのチェックが二重になってしまっているのも無駄のひとつだろうと。

で、調べてみるとどうやらhotplugを使わない変わりにudevで処理をしているらしい。

udevがどういう処理をしているのかの詳細は他のドキュメントに譲るとして、できあがった設定ファイル・スクリプトをもとに設定方法をメモとして残しておこう。

まず、udevに認識させる方法。というか、認識自体は最初からしているみたい。

udevmonitor -e

とかして、抜き差ししてみると、認識していることがわかる。 で、udevは/etc/udev/rules.d/以下にあるファイルを基に認識した後の処理を行っている。 なので、刺したとき、抜いたときに何をするかの処理ルールを記したファイルを作って置いてやればよい。

作ったファイル/etc/udev/rules.d/20-usbgps2.rules:
# udev rules for usbgps2

BUS=="usb", SYSFS{idVendor}=="04bb", SYSFS{idProduct}=="093c", ACTION=="add", RUN+="/usr/libexec/gpsd-launcher-usbserial start $env{DEVPATH} ftdi_sio vendor=0x04bb product=0x093c" 
BUS=="usb", ENV{PRODUCT}=="4bb/93c/600", ACTION=="remove", RUN+="/usr/libexec/gpsd-launcher-usbserial stop $env{DEVPATH} ftdi_sio"

1行目が刺したときで、2行目が抜いたとき。RUN+=よりも前の部分は認識した際の判定条件。刺したときと抜いたときで判定条件が異なるのは、処理をするタイミングの違いからきます(たぶん)。刺したり抜いたりすると、単純に抜き刺しを認識するのではなく、いろんなことをいろんなタイミングで認識します。で、いろいろ試した結果、これが一番ちゃんと動くのです。刺したときは一番最後のタイミング、抜いたときは一番最初のタイミングで処理をしています。

RUN+=は刺したり抜いたりしたときに実行する処理を記述。カーネルモジュールを組み込むだけでなく、gpsdを起動する必要があったので、まとめて別スクリプトにしました。

抜き刺ししたときのスクリプト /usr/libexec/gpsd-launcher-usbserial:
#!/bin/sh

STARTSTOP=$1
shift
DEVPATH=$1
shift

DEVKEY=`echo $DEVPATH|cut -d/ -f4`
DEVNUM=`grep "$DEVKEY" /proc/tty/driver/usbserial | cut -d : -f 1`

case "$STARTSTOP" in
        start)
                if [ $# -gt 0 ]; then
                        /sbin/modprobe $*
                        DEVNUM=`grep "$DEVKEY" /proc/tty/driver/usbserial | cut -d : -f 1`
                fi
                /usr/sbin/gpsd -n -F /var/run/gpsd-$DEVNUM.sock /dev/ttyUSB$DEVNUM
                ;;
        stop)
                GPSDPID=`ps ax|grep /usr/sbin/gpsd | grep ttyUSB$DEVNUM | awk '{print $1}'`
                kill $GPSDPID
                if [ $# -gt 0 ]; then
                        /sbin/modprobe -r $*
                fi
                ;;
esac

デバイスの情報から、どのデバイスファイルが使えるか調べてgpsdに渡すようにしています。

で、ここまででちゃんと動いて、起動も速くなって、さぁ、よかったと思っていたら別の問題が。

なぜか起動時に認識されません。起動後、usbgps2を抜き差しすればちゃんと認識するし、他のデバイスはそんなことしなくても認識する。

うーむなんでだろう。で、udevまわりでいろいろ試していたら、udevtriggerを使えば後から再認識させることができることがわかったので、initスクリプトでこれを実行して、起動時にusbgps2を認識させることに。

/etc/init.d/usbgps2-late-trigger:
#!/bin/bash
# wakeup usbgps2 device
#
# chkconfig: 2345 99 05
# description: wakeup usbgps2 device
#
# Source function library.
. /etc/rc.d/init.d/functions

start() {
        echo -n $"udevtrigger for usbgps2: " 
        udevtrigger --attr-match=idVendor=04bb
        echo
}

case "$1" in
start)
        start
        ;;
stop)
        ;;
status)
        echo modules:
        lsmod|grep ftdi_sio
        echo processes:
        ps ax | grep /usr/sbin/gpsd | grep -v grep
        ;;
*)
        echo $"Usage: $0 {start|stop|status}" 
esac
このスクリプトを作っておいて、
/sbin/chkconfig --add usbgps2-late-trigger
でサービスに加えて完了。

無事に、起動時に認識させることができるようになりました。

さてさて、BIOSでの処理もちょっと時間がかかっていたので、いろいろチェック項目を切って再計測。 実際の起動時間はどれくらいになったかというと、

1分5秒

まで縮みました。

内訳:
  • BIOSチェック 20秒
  • grub 3秒
  • OS起動 25秒
  • Xおよびデスクトップ起動 17秒

BIOSチェックでもう少しと、grubの待ち時間を0にすれば1分は切れそうかな。

Posted by TechStrom on Friday, September 19, 2008