概要
PT3などのチューナデバイスのLinux版ドライバには、独自のAPIで実装されたchardev版のドライバと、LinuxTVのインターフェイスに準拠したDVB版があります。DVB版ドライバで動くデバイスが複数存在する場合、起動時に/dev/dvb/adapter0などにマウントポイントが作成されます。が、この数字は単純にドライバが読み込まれた順番みたいで、うまく制御する方法が見つからなかった(udevルールなども調べたがチューナ情報によってシンボリックリンクを貼る場所を変える処理ができず断念)ので、どうにかして固定しようというのが目的です。
Pythonスクリプトを書く
とりあえず/dev/dvb/adapter0とかに自動で生える部分はうまく制御できなそうだったので、起動後に次のようなPythonスクリプトを実行し、シンボリックリンクを貼ることにします。
方針としては、DVBデバイスに対してioctl経由で、FE_GET_INFOというコマンドを実行します。詳細については公式ドキュメントにかいてあります。ここからGETすると、dvb_frontend_infoという構造体が帰ってきます。この構造体の中に、nameというフィールドがあり、ここを見るとどのチューナかわかるという仕組みです。今回の場合は、PT4KとPT3の区別をしたいので、「Turbosight TBS 6812 (Dual ISDB-T/S/S3)」の場合は/dev/pt4k/adapter{k}に、「Toshiba TC90522 ISDB-S module」の場合(PT3の場合)は、/dev/pt3/adapterS{k}に…というように処理しています。ISDBScannerの処理と同じです。
import ctypes
import glob
import fcntl
FE_GET_INFO = 0x80A86F3D
class DvbFrontendInfo(ctypes.Structure):
_fields_ = [
("name", ctypes.c_char * 128),
("type", ctypes.c_uint),
("frequency_min", ctypes.c_uint32),
("frequency_max", ctypes.c_uint32),
("frequency_stepsize", ctypes.c_uint32),
("frequency_tolerance", ctypes.c_uint32),
("symbol_rate_min", ctypes.c_uint32),
("symbol_rate_max", ctypes.c_uint32),
("symbol_rate_tolerance", ctypes.c_uint32),
("notifier_delay", ctypes.c_uint32),
("caps", ctypes.c_uint),
]
def synbolic_link_rule(path: str) -> str:
if path == "Turbosight TBS 6812 (Dual ISDB-T/S/S3)":
return "/dev/pt4k/adapter{k}"
elif path == "Toshiba TC90522 ISDB-S module":
return "/dev/pt3/adapterS{k}"
elif path == "Toshiba TC90522 ISDB-T module":
return "/dev/pt3/adapterT{k}"
return None
devices = glob.glob("/dev/dvb/adapter*/frontend*")
count_dict = {}
for device in devices:
with open(device, "rb", buffering=0) as f:
fe_info = DvbFrontendInfo()
fcntl.ioctl(f, FE_GET_INFO, fe_info)
name = fe_info.name.decode()
path = synbolic_link_rule(name)
if path in count_dict:
count_dict[path] += 1
else:
count_dict[path] = 0
print(path.format(k=count_dict[path]))
Systemdユニットを作る
起動時にシンボリックリンクを貼ってほしいので、Systemd Unitを作ります。After=systemd-udevd.serviceとすることで、一応udevdが動いてから立ち上がるようにしています。/dev/以下にシンボリックリンクを作りたいため、rootで動くので注意です。
[Unit]
Description=Tuner Symboliclink Script
After=systemd-udevd.service
[Service]
ExecStart=/usr/bin/python3 <Pythonスクリプトの場所>
Restart=no
User=root
Group=root
[Install]
WantedBy=multi-user.target
最後に
ioctlのような低レイヤっぽいのを手軽に叩けるスクリプト言語としてPythonは良いかもしれない。。。