ひこぽんのーと

覚書と雑記です。

Xanadu Next on Wine 4.xのこと

Xanadu NextというPCゲームがある。
今となっては古いゲームでDiabloタイプのARPGなのだが、
なぜか無性にやりたくなる時期がある。

https://www.falcom.co.jp/xanadu_next/

持っているソフトはWindows XPの頃のものだ。
Windows 10上で問題なく動かせるとは思うが、
クソ重いWindowsを起動したくない。

そう思ってLinux上のWineを使って起動しても
テクスチャが虹色になる妙なバグのため、
ずっと遊べないでいた。

ところが最近になって解決法がWine HQのバグ掲示板に載っていたので
ここにメモしておく。

bugs.winehq.org

  1. winetricksを使ってd3dx9_43、d3dcompiler_43をインストールし、同dllがネイティブ版で動作するように設定する。
  2. d3d8to9*1からd3d8.dllをダウンロードし、wine環境のsystem32へ格納
  3. Xanadu Nextをインストールして起動

10年ぶりくらいの念願がかなってよかったよかった。

2ポート コントローラ変換アダプタを使うのこと

前回の続き

よくよく周りを整理してみると、
PS1/PS2コントローラ変換アダプタがあちこちにゴロゴロしている。

サンワサプライのJY-PSUAD21 という14、5年前のアダプタも所持している。
1本のケーブルでコントローラが2つ挿せる製品で、
対戦ゲームをやったりするのに便利かと思って買ったのだが、
対戦する機会もあまり無かったので使わなくなってしまった。

また、Linuxではボタンの数がやたらと多いコントローラとして1ポート分しか認識されず、
2P側は死んでいた。

前回、コントローラについて色々調査したので、
今回はコイツをまともに使う方法を調査してみた。

調査

JY-PSUAD21で検索

LinuxでPSコントローラを使うことを研究してた人の記事の中に、
JY-PSUAD21の2P側が認識されない問題が記事になっていた。

kakurasan.hatenadiary.jp

内容を眺めてみると、どうもusbhidドライバのフラグ「HID_QUIRK_MULTI_INPUT」が絡んでいるようだ。
記事の著者はカーネルソースを修正し、カーネルの再構築を行うことで、
2Pポートを使用できるようにしたようだけど、
正直、それは面倒だし、そもそもそんな知識もない。

HID_QUIRK_MULTI_INPUT

HID_QUIRK……前回、自作ドライバを有効化するために、
modprobeのコンフィグに記述したフラグは「HID_QUIRK_IGNORE」で、
今回が「HID_QUIRK_MULTI_INPUT」。
まさか、同じ定義で行けるのか?

実践

/etc/modprobe.d/blacklist.confに追加

ヘッダで値を調べるとHID_QUIRK_MULTI_INPUT = 64。
コンフィグにコントローラのIDを追加してフラグを立ててみた。

# vendor_id, product_id, HID_QUIRK_IGNORE = 4, HID_QUIRK_MULTI_INPUT = 64
options usbhid quirks=0x054c:0x0268:0x04,0x0d9d:0x3014:0x40

念の為、initcpioを再作成してから再起動した。

効いた

1つのデバイスで2つのコントローラとして認識されるようになった。

欲が出た

このコントローラ、Raspberry Pi上のLakkaで使っていたので、
Lakkaでも2ポート対応にしたい。

やってみた……がだめだった

LibreELECでは、/etc/modprobe.d配下にblacklist.confを定義することで、
モジュールのロード制御ができるようだったので、
同じ方式でoptionを書いてみたのだが、結果はだめだった。
なんでやねん。

lakka usbhid optionsで検索

Retroarchのgithubの記事が出てきた。
github.com

これまたざっくり見ているとオプションを指定するのは間違いないが、
記述場所が違うようだ。
/flash/extlinux.conf:の起動パラメータに追記しろなんてあるけど、
Lakkaの/flash配下にはextlinux.confなんてない。

forums.libretro.com
こっちの記事でもいろんなことが書かれているが、
「『cmdline.txt 』に『usbhid.quirks=0x16c0:0x05e1:0x040』を追記すりゃいいんじゃねーの」
との発言がヒントになった。

実践

cmdline.txtは読み込み専用なので、ターミナルでは編集できない。
LakkaのSDカードをPCでマウントして、PC上で編集する。
cmdline.txtの起動パラメータの最後に『usbhid quirks=0x0d9d:0x3014:0x40』を追記し、
Lakkaを起動した。

効いた

Lakkaでも2つのコントローラとして認識されるようになった。

コントローラを使うために頭をひねったところで、
『所詮、ゲームをするためなんでしょ』と言われ、
褒めてもらえないのがちょっとさみしい。

デバイスドライバを書いたこと

事の発端

コントローラのヘタリ

Logitec Wireless Gamepad F710の調子が悪いので、
分解メンテしてみようとしたが、特殊ネジで開けられなかった。
仕方ないので新しいのを買おうと物色していた。

最近、ゲームコントローラが高い。

ワイヤレスだったり、電池内蔵だったり、振動機能があったりして、
昔より高機能化しているのはわかるが、
1つ3000円から5000円位する。
(Sonyの純正PS4コントローラはもっと高い)
その価格が高いか安いかにかかわらず、
使ってみるまで使用感に満足できるかわからないので、
あまり高額なものは買いたくない。

というわけで、PS2のコントローラをPS3、PC用に変換できるケーブルをAmazonで買った。
ノーブランド品の為、説明書もサポートもドライバもない。(紙の箱には入ってた)
でも、送料込みで500円は安いし、PS2コントローラの使用感はよく知っている。
なにより、PS2コントローラは数があるので中古品ジャンクで格安で買える。
f:id:nagamitsu1976:20190903103426j:plain
こんなの。

安物買いの銭失い

送られてきて早速、確認。

PS3

まぁ、動く。挙動がおかしい時も稀にあるけど、使えなくはなかった。

Windows 10

HIDデバイス ゲームコントローラとして認識され、すべてのキーが正しく反応した。
ゲームでは使ってないけど、まぁ、大丈夫であろう。

Linux

HIDデバイス ゲームコントローラとして認識されるが、ボタン配置がデタラメな上、
○、×、□ボタンの信号が認識されず、反応がない。

まさに、おいおい、である。
メインで使う予定のLinuxで使えないのが痛かった。
開発社的にも世間的にも「PS3Windowsで使えるからOKでしょー」なんだろうが、
オレサマ的にはNGな品でした。

諦めきれなかった

目的が達せられなかったので、500円とはいえ損である。
Windowsでまともに使えるだけに悔しかった。
なんとか使う方法を考える日々が続いて、
PS3Windowsでは全ボタンが正しく押せることから、
信号自体はコントローラからLinuxに送られているのではないか、
という、推測のもと、デバイスドライバを作ってみるか、と思いたった。

本編

調査

ドライバなど作ったことが無いので、作り方を調べる必要があるが、
その前に、本当にコントローラの信号が届いているか調べる必要がある。

lsusb

lsusbコマンドでコントローラが認識されているか確認する。
ボタン配置がデタラメなのはわかってるので、
認識されているはずだが、今一度確認。

$ lsusb
......
Bus 002 Device 013: ID 054c:0268 Sony Corp. Batoh Device / PlayStation 3 Controller
......

Sony云々と出るのはご愛嬌。
正式に許可を得た商品ではなさそうだし、PS3で認識される為にIDを偽装しているのだと思う。

hidusb-dump

hidusb-dumpコマンドを使うと、USBデバイスからの送信データが参照できるので、
ボタンのプッシュ/リリース動作で値が変わるかどうかを観察すれば、
信号が来ているかがわかる。
このコマンドはroot権限がないと実行できない。

$ sudo usbhid-dump -a 002:013 -e all
......
002:013:000:STREAM             1567477856.950528
 01 00 00 00 08 00 64 5D 80 64 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 03 EF 14
 00 00 00 00 23 03 77 01 00 02 00 02 00 01 80 02
 00
......

こんな感じでデータが流れ続けた。
つないでいる限りデータが垂れ流されているようだ。
(ちなみに、Logitec Wireless Gamepad F710の場合、
ボタンを押したときのみデータが送信される方式だった。
どっちがいいかは、まぁ、わからんが、後者のほうがエコだよな)

この状態でコントローラのボタンを押すと、
押している間だけバイト値が変わることが
全ボタンで確認できたので、信号は来ている、という確証を得た。

コーディング

前置きが長くなったけど、
Arch Linux上で動く上記コントローラ用のドライバを書いた。
この記事を参考に、ほぼ丸パクリの形で作った。

Linuxでペンタブモジュールを作成しよう。 - memomuteki

このサイトでは対象がペンタブレットだったので、
ゲームパッド用の定義については、別途、こっちのページを参考にした。
また、定数なんかはlinux/input.hを直接見た。

4. Linux Gamepad Specification — The Linux Kernel documentation
Linux Input Subsystemの使い方

USBデバイス カーネルドライバの作り方は割と情報量が多く、
上記以外にも参考になるサイトはいくつかあった。

運用

ロード問題

参考サイトではドライバのロードを以下の手順で行っていた。

  1. usbhidドライバのデタッチ
  2. 自作ドライバの削除(すでにロードされている場合)
  3. 自作ドライバの登録

開発時はこれで問題ないが、
PCを再起動したり、コントローラを抜き差しする度に、
ドライバのロードを行わければならず、日常的な運用では不便すぎる。

modprobe

カーネルドライバを自動ロードする仕組みにmodprobeがあるので、
自作ドライバをmodprobeに登録して自動的にロードするように設定する。
以下、Arch Linuxの場合。

  1. /lib/modules/extramodules-ARCH/にモジュールを置く。
  2. /etc/modprobe.d/blacklist.conf*1に定義を書く。
  3. /etc/mkinitcpio.confのFILEの項に2.のパスを追加する。
  4. depmod -aを実行する。
  5. mkinitcpio -p linuxを実行してinitcpioを再作成する。
  6. 再起動
/etc/modprobe.d/blacklist.conf
/etc/modprobe.d/blacklist.conf
......
# vendor_id:product_id: HID_QUIRK_IGNORE = 4,……
options usbhid quirks=0x054c:0x0268:0x04
......

これを書かないとusbhidドライバがロードされてしまい、
自作ドライバが適用されないので必ず作成する。

/etc/mkinitcpio.conf
/etc/mkinitcpio.conf
......
# FILES
# This setting is similar to BINARIES above, however, files are added
# as-is and are not parsed in any way.  This is useful for config files.
FILES=(/etc/modprobe.d/blacklist.conf)
......

ここにblacklistの定義を追加しないと、blacklistが有効にならない。

結果

コントローラをつなぐ度に自作ドライバがロードされ、
いつでも正しく使えるようになった。

オチ

実は約20年くらい前に買った
PS2 -> PC用 USBジョイスティック変換コネクタをまだ持っていた。
コイツは出来が悪くストレスフルだったので、ずっと使ってなかったのだが、
同じようにドライバを作って使ってみたら、すこぶる快適な動きになった。*2
そのようなわけで、今回買った変換コネクタは引き出しの奥に行くことになり、
結局、500円の無駄な出費になった。

おあとがよろしいようで。

*1:ファイル名は何でもいい

*2:むろん、動作の調整もしたけどね

cdemu-clientのこと

OSを入れ直して、
改めてcdemu-clientをインストールした際、
起動までに手間取ったのでメモを残しておく。

cdemu-clientなり、gCDemuなりをインストールすると、
cdemu-daemonサービスもインストールされる。
クライアント側はデーモンサービスに対してやり取りをするわけだが、
vhba.rulesファイルが無い場合、起動に失敗する。*1
したがって下記にファイルを追加するといい。

/etc/udev/rules.d/vhba.rules
------
KERNEL=="vhba_ctl", MODE="0660", OWNER="root", GROUP="cdrom"

その後、systemctlで起動なり、有効化するなりすれば、
クライアントは使えるようになる。

*1:ここのPackaging Guidelineに書いてある。 https://cdemu.sourceforge.io/about/vhba/

Arch LinuxとLakkaのデュアルブート構成のこと

LinuxとLakkaを同一ディクス上でデュアルブート構成にしたい

動画を見てたらやっている人がいたので、
「どうにかすればできるんだ」という薄い根拠のもと、チャレンジしてみた。
簡単そうだけど、やってみたら結構めんどくさかった。
また、意外に実現方法の記事が見当たらなかった。
ちなみに、Lakkaは公式にはデュアルブート非対応とある。

以下に方法を残す。

ここでの前提(というか環境)

LakkaをPCへインストールする

LakkaのUSBインストーラを作成し、PCをUSBブートする。
USBメディアにLive環境を作り始めるので終わるまで待つ。
(サイズの小さいUSBメモリのほうが早いだろうなぁ)

再起動後、ブートローダが表示されたら、すかさずTabキーを押す。
Tabを押すと、Live環境の立ち上げとインストーラの立ち上げを選択できるので、
インストーラを立ち上げる。

インストーラからインストールするHDDを選択し、
2度の確認をOKして、インストールする。
インストールが始まると、ディスク全体がLakkaのみになる。
インストールが完了し、再起動してLakkaが起動すればOK。

パーティションの修正

インストール後は、以下のようにパーティション構成が書き換えられている。

パーティション 用途 ファイルシステムラベル
/dev/sdx1 Lakkaブート領域 System
/dev/sdx2 Lakkaデータ領域 Storage

これをこんな風に変える。

パーティション 用途 ファイルシステムラベル
/dev/sdx1 Lakkaブート領域 & Arch Linux ブート領域 System
/dev/sdx2 Lakkaデータ領域 Storage
/dev/sdx3 拡張領域
/dev/sdx5 Arch Linux ルート領域 Arch Linux
/dev/sdx6 共用データ領域 User Data
/dev/sdx7 スワップ
Lakkaデータ領域のバックアップ

ファイル操作のできるLive CDやUSBを用意して(ここではArch LinuxのUSBインストーラ)、
Lakkaデータ領域にあるすべてのファイル・ディレクトリ(隠しファイルも含む)を
別のメディアにコピーする。

パーティションの編集

fdiskやcfdiskを使ってパーティションを編成する。
Lakkaデータ領域をリサイズして、空き領域に必要なパーティションを作るイメージ。
この時、Lakkaブート領域は変更しないこと。

パーティションのフォーマット

Lakkaデータ領域はリサイズの影響で壊れているので、
mkfs.ext4コマンドでフォーマットする。

mkfs.ext4 /dev/sdx2

新たに作成したパーティションも適時フォーマットする。

Lakkaデータ領域の復元

別のメディアにコピーしておいたLakkaデータ領域の全ファイル・ディレクトリを
元のパーティションにコピーする。
tune2fsコマンドでファイルシステムラベルをつける。

tune2fs -L "Storage" /dev/sdx2

ついでに他のパーティションにも名前をつけておくと良いかも。

ここで一旦再起動して、Lakkaが起動することを確認する。

Arch Linuxのインストール

Arch Linuxのインストールメディアを使用してインストールを行う。
Lakkaブート領域をArch Linuxのブート領域としても使うよう設定する。
GRUB2をインストールして、既存のブートローダを上書きする。
再起動後、GRUB2からArch Linuxが起動できればOK。
Lakkaはこの段階で一旦、起動できなくなる。

/etc/grub.d/40_customの編集

LakkaをGRUB2から起動できるように、
/etc/grub.d/40_customにメニューエントリを追加する。

nano /etc/grub.d/40_custom
----
menuentry "Lakka" {
	search --set=root --label System --hint hd2,msdos1
	linux /KERNEL boot=LABEL=System disk=LABEL=Storage quiet
}
----

grub.cfgの再生成

grub-mkconfigを実行してgrub.cfgの再生成を行う。

 grub-mkconfig -o /boot/grub/grub.cfg

再起動後、GRUBメニューにLakkaがあり、問題なく起動できればOK。

ああ、めんどくさかった!
UEFI環境でGPTの場合はなんか違うんだろうか、と思いつつ、
おしまい。

Lakkaのethernet, wifiに静的IPアドレスを設定するのこと

Raspberry Pi 3 B+にインストールしたLakkaで静的IPアドレス設定方法を残しておく。

Ethernetの場合

IP確認

LanケーブルをつなぐとまずはDHCPでプロファイルが作られる。
Lakkaの情報メニューから付与されたIPアドレスを確認する。

ネットワークサービス名の確認

Lakkaはconnmanctlでネットワーク設定を行うので、SSHで作業を行う。
ネットワーク設定は、/storage/.cache/connman/配下にある。
Ethernetならば「ethernet~」、Wifiならば「wifi〜」というディレクトリができているが、
このディレクトリ名がconnmanctlでのサービス名にあたる。

静的IPアドレスの設定

サービス名を確認したら、コマンドで設定する。

# connmanctl config <service> --ipv4 manual <ip_addr> <netmask> <gateway> --nameservers <dns_server>

設定が済むと直ちにIPが変わるため、接続が切れると思うので、
再度、LakkaのメニューでIPを確認を行う。
IPアドレスが変更されていればOK.

Wifiの場合

ステルスモードのアクセスポイントへの接続

scanしても見えないので、connmanctlを使って設定を行う。

$ connmanctl  // 対話モードとなる
connmanctl> scan wifi  // アクセスポイントのスキャン
connmanctl> services  // サービス名の表示
connmanctl> agent on  // エージェントを有効化
connmanctl> connect <サービス名: 例:wifi_dc85de828967_38303944616e69656c73_managed_psk>
ここでSSIDとパスフレーズを聞かれる。
入力後、接続確立のメッセージがでればOK.
connmanctl> quit

静的IPアドレスの設定

設定方法はEthernetの場合と同じ。

おしまい。

Raspberry Pi 3のWi-Fi自動起動のこと

Raspberry Pi 3にArch Linux Armをインストールして、
オンボードEthernetWi-FIに個別のIPアドレスを付与する点で
非常にハマったのでメモを残しておく。

Arch Linux Armのネットワーク設定は、
デフォルトの場合、Systemd-Networkdが使われていて、
Ethernetの方は自動認識してくれるが、Wi-Fiは設定を作成しないと接続できない。
そこでWi-Fi接続の際は、WPA_Supplicantの定義ファイルとSystemd-Networkdの定義ファイルを作成する必要がある。

  • WPA_Supplicantの定義 -> Wi-Fi接続設定(SSID、パスワード関連)
  • Systemd-Networkdの定義 -> IPアドレス設定(DHCP、手動接続など)

ところが、これをやってもIPアドレスは振られるものの
なぜかWi-FIから接続できなかった。(結局、原因もわからなかった)

そこで、Systemd-Networkdを使わずにNetworkManagerを使う方針に変更。
nmtuiで接続設定を作成(SSID、パスワード関連およびIPアドレス設定)し、
OS起動時にWi-Fi接続が行われるように設定した。

  • 「自動的に接続する 」をON
  • 「全ユーザーに使用可能 」をON

ところが、起動時にWi-Fi接続は行われなかった。
コマンドを用いて手動起動は確認できた。

nmcli con up <接続定義名>

ところで、うちのWi-Fiルーターはステルスモードで動いている。
WPA_Supplicantでは「scan_ssid=1」の定義を加える必要があったが、
nmtuiではそのような項目は無かったように思った。
そこで、nmcliで各プロパティを見ていると、
「802-11-wireless」の項目に「hidden」というプロパティがあるのに気づいた。
マニュアルによるとデフォルトはFALSEらしい。

結局、NetworkManagerでWi-Fi自動起動ができた。
ステルスモード時は「802-11-wireless.hidden」を「TRUE」にする必要がある。

nmcli connection edit <接続定義名>
nmcli > set 802-11-wireless.hidden TRUE
nmcli > save
nmcli > quit

結局、Systemd-Networkdでできなかった理由はわからないままか。。。
おしまい。