目次を開く

「電子辞書でLinuxが動く」と聞いて、microSDを1枚用意した。

起動はすぐにできた。そこから先、音が出ない、. が止まらない、突然固まる、ブラウザーが重い、といった問題に1つずつ当たった。直せたものと、直せていないものを残す。

01

何ができて、何が残ったか

SHARPの電子辞書 Brain PW-SH3 で、Debianベースの Brainux を日常的に触れる状態にした。OSの導入そのものは公式の手順どおりで、この記事では導入後に独自に行ったことだけを書く。

項目結果
内蔵スピーカー / マイク動作。音声IC(ROHM BU26154)のLinuxドライバが無かったので書いた。スピーカー再生は耳で、録音はデータの解析で確認。
記号キーで . や / が連続入力される修正。キーボードドライバがキーの「離した」を通知し忘れるバグだった。
USB Wi-Fi動作。公式イメージには wpasupplicant とファームウェアが無く、追加が必要だった。
Bluetooth / WireGuardカーネルを再ビルドして有効化。ビルドと起動は確認、実際の接続は未確認。
固まる問題原因はメモリ不足(OOM)。512 MBのスワップで解消。
microSDからの直接起動動作。辞書の画面を経由せずにLinuxが起動する。
WebブラウザーとAIアプリ本体では実用にならない。PCで動かしてVNCで映す方法が実用的だった。
電源オフ未解決。シャットダウン後に自動で起動し直す。

02

対象と前提

項目内容
本体SHARP Brain PW-SH3(2016年のモデル。Brainuxでの呼び方は Sx3)
SoC / RAMNXP i.MX283(ARM926EJ-S、454 MHz)/ 128 MB(Linuxから見えるのは約111 MB)
画面854×480、16ビットカラー(RGB565)
Brainux2026-03-25 のリリース。Debian 13(trixie)、armel、カーネル 6.1.70
内蔵ストレージeMMC 8 GB。Linuxでは mmcblk0。辞書のシステムが入っているので触らない
microSD32 GB。Linuxでは mmcblk1
USBMicro-Bが1つ。BrainuxではUSBホストとして動く(OTGアダプタで機器を挿す)
ビルド用PCLinux、Docker。buildbrain のDockerイメージを使用
裏ぶたと内側のカバーを外したBrain PW-SH3。黒いキーボード基板の右上に、緑色のメイン基板が載っている。
裏ぶたと内側のカバーを外したところ。黒い大きな基板がキーボードで、右の緑の基板がメイン基板。メイン基板は本体の4分の1ほどしかない。

イメージの書き込み、起動の仕組み、対応機種は公式に任せる。Brainuxの公式サイトとbuildbrainを先に読んでほしい。

最初にやっておくとよいこと

初期ユーザーのパスワードは公開されている値なので、すぐ変える。SSHのホスト鍵も配布イメージに含まれているものは全員共通なので、作り直す。本体で鍵を作るときは Ed25519 と ECDSA だけにする。RSA鍵の生成は、この本体では何分待っても終わらなかった。

bash
# 本体で実行(root)。RSAは作らない
rm -f /etc/ssh/ssh_host_*
ssh-keygen -q -t ed25519 -N "" -f /etc/ssh/ssh_host_ed25519_key
ssh-keygen -q -t ecdsa -N "" -f /etc/ssh/ssh_host_ecdsa_key
systemctl restart ssh

03

カーネルを作り直す

公式のカーネルには Bluetooth も WireGuard も入っていない。buildbrain のツリーで、設定の断片を足して作り直した。組み込み(=y)にしておくと、差し替えるのは zImage だけで済む。

  • bluetooth.config:Bluetooth本体、USBドングル(btusb)、HID、RFCOMM、BNEP、RFKILL
  • wireguard.config:WireGuard、ポリシールーティング、nftables(wg-quick で全通信をVPNに流すときに要る)
bash
# PC で実行。buildbrain を clone し、linux-brain のサブモジュールを取得済みとする
cd buildbrain
make docker-build
docker run --rm -u "$(id -u):$(id -g)" -v "$PWD/..":/w -w /w/buildbrain buildbrain-builder:local bash -lc '
  make ldefconfig &&
  cd linux-brain &&
  scripts/kconfig/merge_config.sh -m .config ../../bluetooth.config ../../wireguard.config &&
  make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- olddefconfig &&
  cd .. && make lbuild'
# できたもの: linux-brain/arch/arm/boot/zImage と dts/imx28-pwsh3.dtb

リリース名を変えない

ソースに手を入れてビルドすると、カーネルのリリース名の末尾に -dirty が付く。名前が変わると /lib/modules/ の場所がずれて、モジュールが読み込めなくなる。ツリーの直下に .scmversion を置くと、名前を固定できる。

bash
# linux-brain の直下で。値は元のリリース名の末尾に合わせる
printf -- '-ga9f534c7f53e' > .scmversion
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -s kernelrelease   # 6.1.70-ga9f534c7f53e

本体に入れる

起動用の領域(/boot、FAT)は読み取り専用でマウントされている。書き込むときだけ書き込み可能にする。元のファイルは残しておく。

bash
# 本体で実行(root)。zImage.new は scp などで /tmp に置いたもの
mount -o remount,rw /boot
[ -e /boot/zImage.bak ] || cp /boot/zImage /boot/zImage.bak
cp /tmp/zImage.new /boot/zImage.new && sync && mv /boot/zImage.new /boot/zImage && sync
mount -o remount,ro /boot

公式イメージには /lib/modules が入っていない。モジュールを使うなら、modules_install で作った一式も本体に置く。

04

キーボード:連続入力のバグと、足りないキー

. や / が止まらない

記号キーを押しながら M を押すと . が入る。ところが、入力が止まらず、同じ文字が連続で入り続けることがあった。/(記号+−)、,(記号+N)、4(記号+R)、=(記号+F)でも起きる。

原因は、キーボードドライバ drivers/input/keyboard/brain-kbd-gpio.c にあった。このドライバはキーを7つのグループ(バンク)に分けて読む。あるバンクの中でキーを離したとき、同じバンクの別のキーがまだ押されていると、「離した」をLinuxに通知しない。記号キーは R・F・N・M・− と同じバンクにあるので、記号を押したまま文字キーを離すと、その文字が押されたままの扱いになり、キーリピートが止まらなくなる。

c
/* 修正前(要点): バンクに押されたキーが残っている間は、状態を消すだけで通知しない */
if ((in[j] & bank) == 0) {
        /* 押された → input_report_key(..., 1) */
        kbd->pressed[i][j] = true;
} else {
        kbd->pressed[i][j] = false;      /* ← 離したことが伝わらない */
}

/* 修正後: 押したときに送ったキーコードを覚えておき、離したら同じコードを離す */
} else {
        if (kbd->pressed[i][j])
                bk_gpio_release(kbd, inputdev, i, j);
        kbd->pressed[i][j] = false;
}

修正の全体は kbd-release-fix.patch。押したときのキーコードをキーごとに記録し、離すときは必ず同じコードを離す。記号キーを先に離しても、文字キーを先に離しても、取り残しが出ない。カーネルを作り直して入れ替えたあと、連続入力が起きなくなったことを実機で確認した。

切り分けに使った方法

/dev/input/event0 を直接読むと、ウィンドウマネージャーが横取りするキーも含めて、本体のキーが実際に何を送っているかが分かる。逆に、同じファイルにイベントを書き込むと、キー入力を外から送り込める。ただし書き込んだイベントはドライバを通らないので、今回のようなドライバのバグは再現しない。

足りないキーを割り当てる

PW-SH3用のデバイスツリー(imx28-pwsh3.dts)では、いくつかのキーが未割り当てだった。使いやすいように割り当てた。変更は keymap-pwsh3.patch。

本体のキー送るキー用途
ホームSuperウィンドウマネージャーのショートカット用
ツールF12Window Makerのメニュー
次ページF11Window Makerのウィンドウ一覧
履歴・しおり半角/全角VNC越しにPCの日本語入力を切り替える
記号+ツール / 記号+次ページF1 / F2ログイン画面(ly)の電源オフ / 再起動

もとからの割り当てのうち、よく使うものは次のとおり。国語=Tab、検索・戻る=Esc、前ページ=Ctrl、文字切替=Alt、英和・和英=Page Up、マイ辞書=Page Down。数字は記号+Q〜P。

キーの名前はデバイスツリーのコメントから読み取った。実機で押して確かめたのは、文字切替・前ページ・次ページ・ホーム・ツール・国語・↑ の7つ。

05

内蔵スピーカーとマイクを鳴らす

公式のBrainuxは、内蔵の音声に対応していない。起動ログには sgtl5000 0-000a: Error reading chip id -6 と出る。これは評価ボード用の定義が残っているだけで、Brainにそのチップは載っていない。

基板を見ると、音声ICは ROHM BU26154MUV だった。Linuxのドライバは見つからなかったので、データシートを読んで書いた。

Brain PW-SH3のメイン基板の部品面。中央にi.MX283、左上に音声IC、右上にeMMCがある。
メイン基板(MPWSA300031001G)。中央がi.MX283(U101)、左上が音声IC(U601)、右上がSamsungのeMMC(U404)。下の辺に、Micro-B、イヤホン端子、microSDのスロットが並ぶ。基板の管理ラベルは隠してある。
音声ICの拡大写真。刻印はBU26154。
U601の拡大。刻印は BU26154。40ピンの6 mm角で、スピーカーアンプとマイクアンプも入っている。
項目内容確かめ方
制御線I2Cバス0、アドレス 0x1aレジスタを読み、初期値がデータシートと一致
クロックSAIF0のMCLK・LRCLK・BITCLK。i.MX283がマスター再生と録音が動いたことから
再生データSAIF0_SDATA0 → ICのSAI_SDIN再生音を耳で確認
録音データICのSAI_SDOUT → SAIF1_SDATA0録音データの解析
スピーカーICのスピーカー出力に直結。外付けアンプなし再生音を耳で確認
リセット線起動時点で解除済み。GPIOの操作は不要I2Cが最初から応答

データシートの入手

ICの型番は、基板の刻印(BU26154)から分かる。正式な型番は BU26154MUV-E2。データシートは公開されていて、次のところから無料で入手できる。

  • ROHMの製品ページ:「ドキュメント」の欄にデータシートがある。製品は「最終販売」(製造中止を申請中)の扱いなので、ページが無くなる前に手元に保存しておくとよい。
  • 部品の販売店の製品ページ:LCSC(部品番号 C4991521)などに、同じデータシートが置かれている。今回使ったのは、ここにあった Rev.002(2015年10月26日付、89ページ)。
  • 見つからないときは、型番 BU26154MUV-E2 と「datasheet」で検索する。データシートをまとめたサイトにも写しがある。

ドライバを書くときに主に読んだのは、レジスタの一覧(37〜44ページ)、Clock EnableとPLLOEの説明(45ページ)、音量の設定範囲(52ページ)。版によってページ番号がずれることがある。データシート自体は再配布せず、リンクだけを載せる。

ドライバの構成

  • bu26154.c:コーデックのドライバ。I2CでICを設定する
  • mxs-bu26154.c:サウンドカードのドライバ。SAIF0 / SAIF1 とICを結び付ける
  • Makefile:カーネルツリーの外でビルドするためのもの(Makefile という名前で置く)

どちらもカーネルモジュールで、カーネルの入れ替えもデバイスツリーの変更も要らない。I2Cのデバイスとサウンドカードのデバイスは、モジュールが自分で作る。

bash
# PC で実行。カーネルをビルドしたツリーとリリース名が実機と一致していること
docker run --rm -u "$(id -u):$(id -g)" -v "$PWD":/w -w /w/buildbrain/linux-brain buildbrain-builder:local \
  make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- M=/w/audio-driver modules

# 本体で実行(root)。2つの .ko を置いて、起動時に読み込ませる
d=/lib/modules/$(uname -r)/extra
mkdir -p "$d"
cp bu26154.ko mxs-bu26154.ko "$d"/
depmod -a
printf 'bu26154\nmxs-bu26154\n' > /etc/modules-load.d/brain-audio.conf
modprobe bu26154 && modprobe mxs-bu26154
bash
amixer -c 0 sset Master 236          # デジタル音量。最大は 254
amixer -c 0 sset Speaker 10 on       # 0〜25。10 が 0 dB
aplay -D hw:0,0 music.wav            # 16ビット・ステレオ
arecord -D hw:0,1 -f S16_LE -r 44100 -c 2 rec.wav

はまったところ

症状原因と対処
I2Cは応答し、aplay もエラーなく終わるのに無音Clock Enableレジスタ(0x0c)の PLLOE ビットを立てていなかった。PLLを使わなくても1にしないと、ICの内部にクロックが回らない。データシートには1行しか書かれていない。0x0c = 0x05 で解決。
arecord が I/O エラーになるSAIF1は、SAIF0のクロックを借りて動く。HW_DIGCTL_CTRL の SAIF_CLKMUX を 2(EXTMSTR0)にする必要があるが、Brain用の初期化では設定されていない。モジュールの読み込み時に設定するようにした。
regmapのI2C実装が使えないこのICは、読み出しが偶数番地、書き込みがその+1の奇数番地。レジスタは3面あり、0x1c / 0x1d で切り替える。読み書きの関数を自前で書いた。
音量を最大にすると動作が保証されないデジタル音量(0x3e)は初期値が 0xff なのに、表では 0xff が設定禁止。上限は 0xfe。
モジュールを外すとカーネルが不安定になるrmmod の直後に BUG: Bad rss-counter state が出ることを2回確認した。原因は未特定。入れ替えるときは、ファイルを置き換えて再起動する。

耳を使わずに確かめる

スピーカーで既知の周波数を鳴らしながら、マイクで録音する。録音に同じ周波数が現れれば、再生と録音の両方が生きている。今回は 880 Hz を鳴らしている間だけ、録音に 880 Hz の成分が現れた。録音が全部 0 なら、ICにクロックが回っていない。

bash
arecord -q -D hw:0,1 -f S16_LE -r 44100 -c 2 -d 5 rec.wav &
sleep 1; aplay -q -D hw:0,0 tone.wav; wait

対応するサンプリングレートは 8〜48 kHz、形式は16ビットのステレオだけ。録音は左チャンネルにだけ音が入る(ICのADCがモノラルのため)。

分かっていないこと:イヤホンは未確認。挿抜の検出も未対応で、挿してもスピーカーは切れない。音割れは、スピーカーアンプをD級にすると減ったが、残っている。省電力は未対応で、アナログ部に常時通電している。ほかの機種(Yamaha系の音声ICを載せたもの)には使えない。

06

固まる原因はメモリだった

パッケージをまとめて入れたり、SSHの鍵を作ったりすると、本体がまったく応答しなくなることが何度かあった。pingには応答するのに、SSHは接続の途中でタイムアウトする。最初はmicroSDの不調を疑ったが、カーネルのログに答えがあった。

dmesg
Out of memory: Killed process ... (apt-get)
Out of memory: Killed process ... (systemd-hwdb)

RAMは実質111 MBで、公式イメージにはスワップが無い。メモリが足りなくなると、システムは同じデータをmicroSDから何度も読み直す状態になり、負荷(ロードアベレージ)が13を超えて、ほぼ止まる。

bash
# 本体で実行(root)。512 MB のスワップファイル
fallocate -l 512M /swapfile && chmod 600 /swapfile
mkswap /swapfile && swapon /swapfile
echo '/swapfile none swap sw 0 0' >> /etc/fstab
echo 'vm.swappiness=30' > /etc/sysctl.d/90-swap.conf && sysctl -p /etc/sysctl.d/90-swap.conf

スワップを足したあと、151個のパッケージ(482 MB分)を入れ終えるまでに、メモリ不足による強制終了は起きなかった。スワップの使用は最大で約37 MBだった。

パッケージは少しずつ入れる

本体で apt update を回すのは重い。PCで必要な .deb を集めてから本体に送り、数個ずつ入れると安定した。lex01-install-batches は、ライブラリを先に、6個ずつ、優先度を下げて入れる。空きメモリが20 MBを切るか、負荷が4以上の間は待つ。

PC側では、本体の /var/lib/dpkg/status を取り寄せ、それを基準に apt-get install --download-only を実行すると、本体に足りないパッケージだけを依存関係つきで集められる。

bash
# PC で実行(Debian trixie のコンテナの中など)。status は本体から取り寄せたもの
O="-o APT::Architecture=armel -o APT::Architectures::=armel
   -o Dir::State::status=$PWD/status -o Dir::State::Lists=$PWD/lists
   -o Dir::Cache::Archives=$PWD/debs -o Dir::Etc::SourceList=$PWD/sources.list
   -o Dir::Etc::SourceParts=/nonexistent"
mkdir -p lists/partial debs/partial
apt-get $O update
apt-get $O install -y --download-only --no-install-recommends gphoto2 gtkam

そのほか、microSDの空き領域は自動では広がらない。動かしたまま sfdisk で第2パーティションを広げ、partx -u と resize2fs を実行すると、再起動なしで32 GBいっぱいまで使えるようになった。対象は mmcblk1。mmcblk0 は辞書の本体なので、間違えないこと。

07

Wi-FiとBluetooth

USBのWi-Fiドングル用のドライバは、公式のカーネルに最初から入っている(Realtekの rtl8xxxu、Ralinkの rt2800usb、Atherosの ath9k_htc、MediaTekの mt76 系など)。ところが、公式イメージには次の2つが入っていないので、そのままではつながらない。

  • wpasupplicant:無いと、NetworkManagerがWi-Fiを「unavailable」と表示する
  • ファームウェア:firmware-realtek、firmware-misc-nonfree(Ralink)、firmware-atheros、firmware-mediatek。/lib/firmware は空で、aptの設定にも non-free-firmware が無い

本体はネットにつながっていないので、PCで .deb を集めてmicroSDに入れておき、本体で dpkg -i する。確認したドングルは BUFFALO WLI-UC-GNM(Ralink RT8070)。

bash
nmcli device                       # wifi の行が disconnected になっていればよい
nmcli device wifi connect "SSID" --ask

802-11-wireless-security.key-mgmt: property is missing というエラーが出たら、失敗した接続設定が残っている。nmcli connection delete で消して、nmcli device wifi rescan のあとにつなぎ直す。

USB端子は1つしかない。Wi-Fiドングルを挿すと、ほかのUSB機器は同時に使えない。Bluetoothは、カーネル側の準備までで、ドングルを挿しての確認はしていない。

08

microSDからの直接起動と、電源オフの問題

公式イメージの起動用の領域には、nk/ というフォルダがある。その中の機種別のファイルを領域の一番上にコピーしておくと、リセット時に辞書のシステムを経由せず、U-BootからLinuxが直接起動する。PW-SH3 用は edsa3exe.bin。

bash
# microSD の第1パーティションをマウントした場所で
cp nk/edsa3exe.bin ./edsa3exe.bin

内蔵の起動プログラムが、辞書のシステムを読み込む前にmicroSDを調べる仕組みを使っている。内蔵ストレージは書き換えない。microSDを抜くか、このファイルを消せば、元の電子辞書に戻る。再起動の指示から約85〜105秒で、SSHに応答するようになった。

電源オフが再起動になる(未解決)

systemctl poweroff は最後まで進む。しかし、その直後に本体が自動で起動し直す。電源レジスタ(HW_POWER_STS)を読むと、5 Vの入力ありと検出されていた。i.MX28は、5 Vが入っている状態で電源を切ると、すぐに起動し直す。USBのコントローラーを止めても、5 Vの検出は消えなかった。出どころは特定できていない。

起動の途中、U-Bootがカーネルを読み込んだ直後で止まったことも1回あった。OSが動いていないので、電源ボタンは効かない。microSDを抜いてからリセットすると辞書が起動し、そこで電源を切れる。

09

854×480でデスクトップを使う

公式イメージには、X11・JWM・ログイン画面(ly)が入っている。今回はウィンドウマネージャーを Window Maker にした。ユーザーの ~/.xsession に exec wmaker と書くだけで切り替わる。パッケージを入れると、システム全体の標準まで Window Maker に変わるので、ほかのユーザーをJWMのままにしたいなら update-alternatives --set x-window-manager /usr/bin/jwm で戻す。

困ったこと対処
ウィンドウが画面からはみ出す。スクロールバーが画面の外に出るWindow Makerには、ウィンドウを画面に収める機能が無い。アプリごとに「最初から最大化」を設定する(下のコマンド)。
最大化するとDockの下に隠れるNoWindowOverDock = YES。
メニューを開けない(右クリックもF12も無い)キーボード側でツール=F12、次ページ=F11を割り当てた。
タッチでダブルクリックが効かないDoubleClickDelay を250から600 msに延ばした。
Dockの設定ファイルを書き換えても元に戻るWindow Makerは、終了時に WMState を上書きする。書き換えたら chattr +i で保護し、SIGUSR1 で再読み込みさせてから、保護を外す。
標準の端末がgnome-terminalで、起動しないupdate-alternatives --set x-terminal-emulator /usr/bin/lxterminal。
ログイン画面にカーネルのメッセージが重なるkernel.printk = 3 4 1 3 を /etc/sysctl.d/ に置く。
NetSurfでキーを押してもスクロールしない開いた直後は、入力がアドレス欄に向いている。Tab(国語キー)を1回押してから ↑↓。
bash
wdwrite WindowMaker NoWindowOverDock YES
wdwrite WMGLOBAL DoubleClickDelay 600
wdwrite WMWindowAttributes lxterminal.Lxterminal '{StartMaximized = Yes;}'
wdwrite WMWindowAttributes netsurf-gtk.Netsurf-gtk '{StartMaximized = Yes;}'
wdwrite WindowMaker MaximizeKey '"Mod1+Up"'      # 文字切替 + ↑

画面の内容は、SSH越しにフレームバッファを読むだけで取り出せる。追加のソフトは要らない。遠隔で作業するとき、今の画面を確かめるのに使った。

bash
# PC で実行。1708 = 854 ピクセル × 2 バイト
ssh -l root brain.local 'head -c $((1708*480)) /dev/fb0' > fb.raw
ffmpeg -f rawvideo -pixel_format rgb565le -video_size 854x480 -i fb.raw -frames:v 1 screen.png

Python 3は最初から入っている。python3-tk を足すと、tkinterで自作の画面を作れる。ただし、ウィンドウが出るまでに約5秒、少し部品の多いアプリだと約20秒かかる。色数は16ビットが最も軽く、減らす設定は無い。

10

WebとAIアプリは、PCで動かしてVNCで映す

本体でJavaScriptの動くブラウザーを使うのは、現実的ではなかった。FirefoxとChromiumは、armel向けのパッケージが無い。WebKit系は、エンジンだけで約88 MBあり、メモリが足りない。そこで、重い処理はPCに任せ、Brainは画面とキーボードだけを受け持つ形にした。

PCブラウザー / AIアプリ + VNCサーバー(localhostのみ)
↓
経路PCからBrainへのSSH(リモートフォワード)
↓
Brainxtightvncviewer で localhost に接続

VNCをLANに開かない

VNCは暗号化されない。PC側のVNCサーバーは localhost だけで待ち受けさせ、PCからBrainへのSSH接続に乗せて届ける。Brainから見ると、自分の localhost にVNCサーバーがあるように見える。BrainからPCへ入る経路は作らない。

bash
# PC で実行。5905 = 仮想デスクトップ、5906 = 実画面の共有
ssh -N -R 5905:localhost:5905 -R 5906:localhost:5906 -l root brain.local

方法1:仮想デスクトップでブラウザーを動かす

PCに、Brainの画面に合わせた小さな仮想デスクトップを作り、そこでFirefoxを動かす。大きさは 786×446、色は16ビット。Brain側のウィンドウにちょうど収まり、色の変換も要らない。

bash
# PC で実行
Xtigervnc :5 -geometry 786x446 -depth 16 -rfbport 5905 -localhost \
  -SecurityTypes None -AlwaysShared -nolisten tcp &
DISPLAY=:5 marco &
DISPLAY=:5 firefox --no-remote --profile "$HOME/.config/brain-vnc/firefox" --width 786 --height 446 &

# Brain で実行
xtightvncviewer -encodings "tight copyrect hextile" -compresslevel 6 -quality 5 localhost:5

速度は、使った本人の感想で「割と実用的」。ページの表示やスクロールは、本体のNetSurfより快適だった。

方法2:動いているアプリのウィンドウを、そのまま映す

AIのデスクトップアプリのように、同時に1つしか起動できず、実行中の作業を止めたくないものは、起動し直さずに映す。PCの実際の画面のうち、そのウィンドウの範囲だけを x11vnc -clip で配る。

  1. ウィンドウを、Brainに合う大きさ(786×446)にして、最前面に固定する。
  2. その範囲だけを x11vnc で localhost に配る。
  3. Brainのビューアを閉じたら、ウィンドウを元の位置と大きさに戻す。
bash
# PC で実行(要点)。id はウィンドウのID、X Y は移動先の左上
wmctrl -i -r "$id" -b remove,maximized_vert,maximized_horz
wmctrl -i -r "$id" -e "0,$X,$Y,786,446"
wmctrl -i -r "$id" -b add,above
x11vnc -display :0 -localhost -rfbport 5906 -nopw -shared -forever \
  -clip "786x446+$X+$Y" -noxdamage -repeat -quiet -bg

スクリプトの全体は share.sh(PC側)と pcapp(Brain側)。作ってみて分かったことを挙げる。

分かったこと対処
GTKのアプリは、ウィンドウの周りに見えない影の領域を持つ_GTK_FRAME_EXTENTS を読み、その分を引いて位置と大きさを決める。
半透明のウィンドウだと、後ろのウィンドウが透けて映る共有中だけ _NET_WM_WINDOW_OPACITY を不透明にして、終わったら戻す。
最小サイズが大きくて、446の高さにできないアプリがある少し大きく(1058×600)取り、x11vnc -scale 786x446 で縮めて配る。文字は約74%になるが読める。
画面の半分に寄せたウィンドウを戻すと、全画面になってしまう最大化の状態を、縦と横で別々に記録して戻す。
PCがロックされると、操作できなくなる映す範囲を、ロック画面の中央(パスワードの入力欄)に切り替える。Brainのキーボードでパスワードを入れると、PC本来のロック画面が確認する。パスワードなしで解除する仕組みは作らない。
日本語が打てない本体のキーに半角/全角を割り当てる。PCの日本語入力が、そのまま使える。
方法2の注意

映しているのは1つのウィンドウでも、Brainからのキー操作はPCのデスクトップ全体に届く。Brainにログインできる人は、PCを操作できることになる。Brain側のアカウントのパスワードは、推測されにくいものにする。

うまくいかなかった方法もある。アプリを一度終了し、仮想デスクトップ側で起動し直す方式は、動きはするが、実行中の作業が止まる。アプリの環境変数(/proc/PID/environ)から表示先を調べようとしたが、アプリが起動後にその領域を書き換えていて、読めなかった。

11

うまくいっていないこと

項目状況
電源オフシャットダウン後に自動で起動し直す。5 Vの検出の出どころが不明。
Bluetooth / WireGuardカーネルに入れただけ。接続は未確認。
イヤホン未確認。挿抜の検出なし。
バッテリーの充電Brainuxは充電回路を止めたまま動く。回路をオンにする試験では、電池に電流が流れなかった。原因は未切り分け。
microSDの読み取りエラーPCのカードリーダーで、読み取りエラーが散発した。読み直すと正常で、ファイルは壊れていない。カードかリーダーかは未切り分け。
Wi-Fiの接続同じ名前のアクセスポイントが2台あり、起動時につなぎ直す。IPアドレスが変わることがある。

キーボードの修正と音声のドライバは、ほかのBrainの利用者にも役に立つはずだが、まだ本家には送っていない。

12

参照資料と公開範囲

  • Brainux導入手順、対応機種、起動の仕組み。まずここを読む。
  • brain-hackers/buildbrainカーネル、U-Boot、イメージのビルド環境。リリースのイメージもここにある。
  • brain-hackers/linux-brainBrain用のカーネル。キーボードドライバとデバイスツリーはここ。
  • ROHM BU26154MUV 製品ページ音声ICのデータシート。レジスタと、クロックの条件。
  • x11vnc / TigerVNC画面の一部を配る -clip と、仮想デスクトップ。

本文は2026年10月2日〜5日の実機での作業記録をもとに編集。家庭内のアドレス、無線LANの名前、アカウント名、認証情報、機器の名前、私用の画面は掲載していません。写真は撮影情報を取り除き、基板の管理ラベルを隠しています。掲載したファイルは、カーネルへの変更(GPL-2.0)と、作業用のスクリプトです。動作は PW-SH3 の1台で確かめた範囲に限ります。

END OF FIELD NOTE 002ハック一覧へ戻る ↗