大破ログ

日々大破、それと側転少々。PC関連その他、気になったことなどをつらつらと。

WAB-I1750-PSのOpenWrtにおける "SERIAL" ポートについて

さて、最近のELECOM公式のセールによってすっかりお馴染みとなったWAB-I1750-PSですが、OpenWrtにおいて "SERIAL" ポートの動作がサポートされました。

留意する点がいくつかある為、まとめていきます。

仕様

  • メーカーファームウェアでのSERIAL ポート

    • コマンドラインによって設定を行うことを目的として、所謂Ciscoケーブルを接続する為のRJ-45ポート
    • 115200bpsで動作
  • OpenWrtでのSERIALポート

    • デフォルトではコンソールの割り当ては無し
      • Enterキーを押しても改行されていくだけで、シェルは表示されず、操作は不可
    • Linux Kernelのデフォルトである9600bpsで動作

OpenWrtにおけるSERIALポートの使用

2024/03/26改訂: WAB-I1750-PSのサポート用コードを変更するほか、OpenWrtのシステム系に手を入れることでLinux KernelやOpenWrtのコンソールをデフォルトで割り当てられそうだ、と思い至ったので変更を試して投げ込み、マージされました。

下記コミット以降において、U-Boot部分とOpenWrtの一部システムメッセージを除いて、 "SERIAL" ポートを "SERVICE" ポートと同様に利用することが可能です。

procd: update to Git HEAD (2024-03-25) · openwrt/openwrt@ff064b6

  • 備考

    • OpenWrtの一部システムメッセージは "SERVICE" ポートにのみ出力され、 "SERIAL" ポート側には出力されない

      • - config restore -
      • - failsafe button <button> was pressed -(failsafeモード移行時)
      • - failsafe -(failsafe移行時)
      • sysupgrade時の Commencing upgrade. Closing all shell sessions. 以降のログ

      など

    • "SERIAL" ポートでOpenWrtのコンソールを利用しない場合、/etc/inittab 内の ttyATH1::askfirst:/usr/libexec/login.sh 行の先頭にシャープ (#) を置いて(前後にスペースは入れない)コメントアウトする

    • "SERIAL" ポートはLinux Kernelの "bootconsole" ではない関係上、Kernelのブート最初期段階からは出力されず、ブート中に ttyATH1 が有効になったタイミングでdmesg先頭からその時点までが一気に出力される

何らかのアプリケーションで /dev/ttyATH1 をオープンするか、ポートにOpenWrtのコンソールを結び付けるなどして使用してください。

  • 共通

    • シェル上でbaudrateをデフォルトの9600bpsから変更する場合は、stty コマンド等を使用する
      • 例: stty -F /dev/ttyATH1 115200
  • OpenWrtのコンソールとして使用

    1. /etc/inittab の末尾に以下を追記
      ttyATH1::askfirst:/usr/libexec/login.sh

    2. WAB-I1750-PSを再起動
      ブート後半でSERIALポートのコンソール上に Please press Enter to activate this console. と表示され、操作が可能になる

    注: firstboot すると /etc/inittab の変更が消失し、コンソールが再び開けなくなるので注意すること。また、sysupgrade時に引き継がれる対象のファイルに含まれていない可能性があるので、その点も注意する。

    なお、追記済みの /etc/inittab ファイルを用意して、Image Builderでそれを組み込んだイメージをビルドすることも可能。

技術的な話

WAB-I1750-PSが搭載しているSoCであるQualcomm Atheros QCA9558の属するQCA955xシリーズでは、プライマリのUARTにはごく一般的な8250互換である16550 UARTを搭載しているが、それに加えてセカンダリとしてAtheros AR933xが搭載するUARTと互換のものを備えている。
前者は "SERVICE" ポートや、それと同一ラインである内部ピンヘッダに割り当てられ、メーカーによるデバッグや復旧用となっている一方で、後者はこの記事で主題となっている "SERIAL" ポートに割り当てられ、ユーザーによる設定用として供用されている。

QCA955x SoCにおいて、16550 UARTは何ら問題無くサポートされ機能する状態であるものの、AR933x互換UARTについてはこれまでQCA955x SoC上ではOpenWrtにおいてサポートされておらず、WAB-I1750-PSのサポートがOpenWrt公式にマージされた時点では使用不可の状態であった。
ただ、それがマージされた時点で少々気になっていた点があり、落ち着いてからDeviceTreeを弄ってみたところ、Linux Kernelへのpatch等は無しで動いてしまった。そこで折角だからとQCA955x SoCにAR933x互換UARTのサポートを追加する変更と、WAB-I1750-PSでそれを有効化する変更を仕立ててOpenWrt公式に投げ込み、マージされた。
これにより、OpenWrt公式のファームウェアでも "SERIAL" ポートが使用できる状態となった。
ちなみに、できればメーカーファームウェアと同じ115200bpsで動作させたかったものの、DeviceTreeプロパティの current-speed がAR933x互換UARTのドライバではサポートされていなかった為、やむなく9600bpsで置いておくことになった。

当初はLinux Kernelのdmesgも "SERIAL" ポートに "SERVICE" ポート同様出力させようとしてみたものの、OpenWrtのプロセス管理ツール(systemdの代替)であるところのprocdによるコンソールの検出ロジックとLinux Kernelによるメインコンソールの取得ロジックが嚙み合わずworkaroundを用いた結果、failsafeモード下において "SERVICE" ポート側の入出力が壊れる問題が発生した為、断念してdmesgは流さないこととした。
具体的にはLinux Kernelがbootargsに存在する複数の console= 引数のうち最後を /dev/console として割り当てるのに対し、procdは最初のものをOpenWrtのコンソールとして取得してしまう為、対象となるコンソールの不一致が起きた。その為の対処として "SERVICE" 側のコンソール (ttyS0) を最初と最後で2回設定したところ、通常起動のOpenWrtコンソールでは問題無いものの、failsafeモードにおいては "SERVICE" 側の入力が壊れた(入力が中途半端な状態で送出される, 前の入力が一緒に送出される等)。

また、/etc/inittab へユーザーによる追記が必要な点については、あくまでWAB-I1750-PSでは ttyATH1 が設定用シリアルコンソールとして供用されているというだけで、それ以外のデバイスでは他の目的で用いられている可能性が絶対に無いとは言い切れない為、ath79/generic の /etc/inittab としてttyATH1をコンソールに割り当てたものを用意することはしなかった。

2024/03/26追記分:

上記のLinux Kernelとprocdのコンソール取得方法の差による問題は、procdにおいてbootargs内に複数の console= パラメータを検出した場合に、特定のコンソールデバイス (/dev/ttyS<n>) の代わりにLinux Kernelが設定済みの /dev/console を使用するように変更することで対処した。
また、OpenWrtのコンソールとして登録する点については、procdがコンソールを探すのに使用する /etc/inittab の内容をブート時に毎回チェックし、OpenWrtがブートされているデバイスがWAB-I1750-PSで、なおかつ ttyATH1::askfirst が存在する場合は何もせずスキップし、存在しない場合はエントリを追加するスクリプトを追加することで対処した。

なお、一部システムメッセージが "SERIAL" 側に出力されないのは、前述の通りprocdが /dev/console/dev/ttyS0("SERVICE" ポート側) が割り当てられたもの) を出力先として使用していることが理由。これについては複数のコンソールに出力できない関係上、U-Bootの出力先である "SERVICE" 側をOpenWrtでも一貫してメインのコンソールとして設定した。
また、U-Bootが "SERIAL" 側で出力されない点については、そもそもU-Bootが "SERIAL" ポートへの出力を想定せず、セットアップも行っていないことが原因なので、どうしようもない。U-Bootを操作したい場合は "SERVICE" ポートを使用する。