はじめに
この記事は「成功しなかった」内容です。
成功しなかった記録を残すものです。どうかこの屍を超えてください。
今回はちょっとニッチな挑戦記録です。タイトルの通り、Buffalo製のUSBビデオキャプチャデバイス「PC-SDVD/U2」を、Raspberry Pi 3で動かしてみようというお話。
え?そんなの挿せば動くでしょ?──そう思っていた時期が私にもありました...(これが言いたかっただけ)
ニッチなデバイスをを使おうとすると一筋縄ではいかぬのがLinux。
環境
- マシン:Raspberry Pi 3 Model B
- OS:Raspberry Pi OS Bookworm 64bit Lite(GUIなし)
- キャプチャデバイス:Buffalo PC-SDVD/U2
-
dmesg
上ではUSB 2863
として認識 - VID:
0411
, PID:015a
-
- カーネル:6.12.25 → 6.12.29(手動ビルド)
- その他ツール:v4l-utils, i2c-tools, media-ctl など
初期の動作
結論から言えば、「何も起きなかった」です。
dmesg
を見ても、VID/PID は確かに表示されるものの、デバイスとしては /dev/video0
はおろか、/dev/mediaX
すら出てこない。つまり、ドライバ(em28xx
系)があたっていない?
usb 1-1.3: New USB device found, idVendor=0411, idProduct=015a, bcdDevice= 1.10
この段階では、modprobe em28xx
や modprobe em28xx-v4l
をしても /dev/video0
は出現せず、v4l2-ctl --list-devices
でも "Cannot open device /dev/video0" のエラーしか出ない。USBデバイスが接続されていても、ドライバがデバイスのVID/PIDとマッチングしない限り、何も起きないようだ。
紆余曲折ののち、ようやく /dev/media3
は現れるようにはなった。
カーネルビルド
em28xx カーネルモジュールをビルドし、VID:0411, PID:015a を持つデバイスを em28xx_id_table[]
に追加していく。調べてみると、どうやら em28xx
ドライバ自体はもともと存在していて、VID/PIDがテーブル上に無い為、USBが接続されても無視されているらしい。
ここからは実際の作業。
ステップ1:カーネルソースを取ってくる
sudo apt install raspberrypi-kernel-headers git bc bison flex libssl-dev make
~$ git clone --depth=1 https://github.com/raspberrypi/linux
~$ cd linux
~$ KERNEL=kernel8
~$ make bcm2711_defconfig
ステップ2:em28xxに自作デバイスを登録
drivers/media/usb/em28xx/em28xx-cards.c
に、自分で定義したカード(EM2863_BOARD_CUSTOM)を追加。
これがないとVID/PIDを見てもドライバ君に「んなボードは知らん」と言われて無視されます。
ボードの定義 (drivers/media/usb/em28xx/em28xx-cards.c)
/*
* Board definitions
*/
const struct em28xx_board em28xx_boards[] = {
[EM2863_BOARD_CUSTOM] = {
.name = "Buffalo USB 2863 (custom)",
.tuner_type = TUNER_ABSENT,
.decoder = EM28XX_SAA711X,
.has_msp34xx = 1,
.has_ir_i2c = 1,
},
[EM2750_BOARD_UNKNOWN] = {
.name = "EM2710/EM2750/EM2751 webcam grabber",
.xclk = EM28XX_XCLK_FREQUENCY_20MHZ,
VID/PIDを自作の定義へ割り当て
/* table of devices that work with this driver */
struct usb_device_id em28xx_id_table[] = {
{ USB_DEVICE(0x0411, 0x015a),
.driver_info = EM2863_BOARD_CUSTOM },
{ USB_DEVICE(0xeb1a, 0x2750),
.driver_info = EM2750_BOARD_UNKNOWN },
ヘッダーファイルにcard IDの登録
/* Boards supported by driver */
#define EM2863_BOARD_CUSTOM 110
#define EM2800_BOARD_UNKNOWN 0
この時点で decoder
は EM28XX_SAA711X
に。
理由はあとで触れますが、「tvp5150」ではなさそうだったからです。
ステップ3:ビルドして入れる!
以下ではRaspberry Pi上でのビルドを想定したコマンドになっているが、母艦PCなどでクロスコンパイルした方が圧倒的に楽で高速なのでそっちがおすすめ。うちの環境ではwslでコンパイルしてscpで転送してました。
make -j$(nproc) Image modules dtbs # Module.symvers is missingの表示が出るので初回だけ実行
make M=drivers/media/usb/em28xx modules
sudo make M=drivers/media/usb/em28xx modules_install
sudo depmod -a
そして……新カーネルを /boot/firmware
に適用
sudo cp /boot/firmware/$KERNEL.img /boot/firmware/$KERNEL-backup.img
sudo cp arch/arm64/boot/Image.gz /boot/firmware/$KERNEL.img
sudo cp arch/arm64/boot/dts/broadcom/*.dtb /boot/firmware/
sudo cp arch/arm64/boot/dts/overlays/*.dtb* /boot/firmware/overlays/
sudo cp arch/arm64/boot/dts/overlays/README /boot/firmware/overlays/
sudo reboot
ステップ4:あらためて動作チェック (失敗)
dmesg
を叩いてどういう挙動になったか見てみる
pi@RPi3:~ $ dmesg | grep em28
[ 6.698677] em28xx: loading out-of-tree module taints kernel.
[ 6.700503] em28xx 1-1.3:1.0: New device USB 2863 Device @ 480 Mbps (0411:015a, interface 0, class 0)
[ 6.700534] em28xx 1-1.3:1.0: Audio interface 0 found (Vendor Class)
[ 6.700542] em28xx 1-1.3:1.0: Video interface 0 found: isoc
[ 6.758247] em28xx 1-1.3:1.0: chip ID is em2860
[ 6.880902] em28xx 1-1.3:1.0: EEPROM ID = 1a eb 67 95, EEPROM hash = 0x9a2fcb2c
[ 6.880934] em28xx 1-1.3:1.0: EEPROM info:
[ 6.880941] em28xx 1-1.3:1.0: I2S audio, 5 sample rates
[ 6.880948] em28xx 1-1.3:1.0: 500mA max power
[ 6.880954] em28xx 1-1.3:1.0: Table at offset 0x24, strings=0x206a, 0x0e8a, 0x0000
[ 6.958092] em28xx 1-1.3:1.0: Identified as Buffalo USB 2863 (custom) (card=110)
[ 6.958127] em28xx 1-1.3:1.0: analog set to isoc mode.
[ 6.982407] usbcore: registered new interface driver em28xx
[ 6.998213] em28xx 1-1.3:1.0: Registering V4L2 extension
[ 7.125565] em28xx 1-1.3:1.0: Config register raw data: 0xf0
[ 7.125595] em28xx 1-1.3:1.0: I2S Audio (5 sample rate(s))
[ 7.125603] em28xx 1-1.3:1.0: No AC97 audio processor
[ 7.798703] em28xx 1-1.3:1.0: failed to create media graph
[ 7.798712] em28xx 1-1.3:1.0: V4L2 device vbi0 deregistered
[ 7.798953] em28xx 1-1.3:1.0: V4L2 device video0 deregistered
[ 7.799137] em28xx: Registered (Em28xx v4l2 Extension) extension
[ 7.827879] em28xx 1-1.3:1.0: Binding audio extension
[ 7.827917] em28xx 1-1.3:1.0: em28xx-audio.c: Copyright (C) 2006 Markus Rechberger
[ 7.827924] em28xx 1-1.3:1.0: em28xx-audio.c: Copyright (C) 2007-2016 Mauro Carvalho Chehab
[ 7.828010] em28xx 1-1.3:1.0: Endpoint 0x83 high-speed on intf 0 alt 7 interval = 8, size 196
[ 7.828024] em28xx 1-1.3:1.0: Number of URBs: 1, with 64 packets and 192 size
[ 7.830579] em28xx 1-1.3:1.0: Audio extension successfully initialized
[ 7.830613] em28xx: Registered (Em28xx Audio Extension) extension
[ 7.911779] em28xx 1-1.3:1.0: Registering input extension
[ 7.911834] em28xx: Registered (Em28xx Input Extension) extension
ここで、
[ 6.958092] em28xx 1-1.3:1.0: Identified as Buffalo USB 2863 (custom) (card=110)
とあることから、VID/PIDが正しく識別されてデバイスドライバが当たっていることが確認できる。
デバイスドライバの読み込み状況は
pi@RPi3:~ $ lsmod | grep em28
em28xx_rc 16384 0
em28xx_alsa 16384 0
em28xx_v4l 45056 0
em28xx 94208 3 em28xx_rc,em28xx_alsa,em28xx_v4l
videobuf2_vmalloc 12288 2 em28xx_v4l,bcm2835_v4l2
tveeprom 20480 1 em28xx
videobuf2_v4l2 32768 5 bcm2835_codec,em28xx_v4l,bcm2835_v4l2,v4l2_mem2mem,bcm2835_isp
videodev 303104 8 bcm2835_codec,videobuf2_v4l2,em28xx_v4l,msp3400,bcm2835_v4l2,em28xx,v4l2_mem2mem,bcm2835_isp
videobuf2_common 73728 9 bcm2835_codec,videobuf2_vmalloc,videobuf2_dma_contig,videobuf2_v4l2,em28xx_v4l,bcm2835_v4l2,v4l2_mem2mem,videobuf2_memops,bcm2835_isp
mc 61440 9 videodev,bcm2835_codec,videobuf2_v4l2,em28xx_v4l,msp3400,videobuf2_common,em28xx,v4l2_mem2mem,bcm2835_isp
snd_pcm 139264 6 em28xx_alsa,snd_bcm2835,snd_soc_hdmi_codec,snd_compress,snd_soc_core,snd_pcm_dmaengine
snd 110592 7 em28xx_alsa,snd_bcm2835,snd_soc_hdmi_codec,snd_timer,snd_compress,snd_soc_core,snd_pcm
となり、em28周辺のドライバが自動で読み込まれていることがわかる。
v4l2-ctl
上にも/dev/media3が出現するようになった。
pi@RPi3:~ $ v4l2-ctl --list-devices
bcm2835-codec-decode (platform:bcm2835-codec):
/dev/video10
/dev/video11
/dev/video12
/dev/video18
/dev/video31
bcm2835-isp (platform:bcm2835-isp):
/dev/video13
/dev/video14
/dev/video15
/dev/video16
/dev/video20
/dev/video21
/dev/video22
/dev/video23
/dev/media0
/dev/media1
USB 2863 Device (usb-3f980000.usb-1.3):
/dev/media3
bcm2835-codec (vchiq:bcm2835-codec):
/dev/media2
Cannot open device /dev/video0, exiting.
一方で、
[ 7.798703] em28xx 1-1.3:1.0: failed to create media graph
[ 7.798712] em28xx 1-1.3:1.0: V4L2 device vbi0 deregistered
[ 7.798953] em28xx 1-1.3:1.0: V4L2 device video0 deregistered
と表示されており、media graph
(こいつがなんなのかよくわからない)の構築に失敗してvideo0デバイスとしての扱いを解除されてしまっている。
またmedia-ctl
でも
pi@RPi3:~ $ media-ctl -d /dev/media3 -p
Media controller API version 6.12.29
Media device information
------------------------
driver em28xx
model USB 2863 Device
serial 200806
bus info usb-3f980000.usb-1.3
hw revision 0x110
driver version 6.12.29
Device topology
pi@RPi3:~ $
となっており、デバイスの基本的な情報は取得できているものの、それ以上の詳細な情報は得られていないようだ。
つまり「em28xx本体」は動いているけれど、それに接続されるべきI2Cデバイスなどとの接続が確立できていない、ということなのだろう。
i2cバス上の謎のデバイス
ChatGPTに言われるがままI2Cを探索 (i2cdetect -l
) してみる。
pi@RPi3:~ $ i2cdetect -l
i2c-1 i2c bcm2835 (i2c@7e804000) I2C adapter
i2c-2 i2c bcm2835 (i2c@7e805000) I2C adapter
i2c-11 i2c 1-1.3:1.0 I2C adapter
i2c-11というのがPC-SDVD/U2内部のI2Cアダプタを指しているらしい。そこで、11を指定して更にその配下の応答を探ると、
pi@RPi3:~ $ sudo i2cdetect -y 11
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- 41 -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: 50 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
pi@RPi3:~ $
となる。見えているのは0x41
と0x50
の二つ。
0x50
はEEPROMのアドレスで、 0x41
がどうやらsaa7113h
らしい?
とりあえずsaa711x
系と目星をつけて、decoderを EM28XX_SAA711X
に。
dmesgにログを吐くように仕掛ける
それでも /dev/video0
は出てこない。
ならば、と em28xx
のソースに pr_info()
を埋め込んでみる。
if (dev->board.decoder == EM28XX_SAA711X) {
struct v4l2_subdev *sd;
pr_info("em28xx: v4l2_init: Attempting to probe SAA711X decoder (expected addr 0x%02x or 0x%02x)...\n",
saa711x_addrs[0], saa711x_addrs[1]);
sd = v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
&dev->i2c_adap[dev->def_i2c_bus],
"saa7115_auto", 0, saa711x_addrs);
if (sd) {
pr_info("em28xx: v4l2_init: SAA711X probed successfully at 0x%02x\n",
v4l2_i2c_subdev_addr(sd));
} else {
pr_info("em28xx: v4l2_init: SAA711X probe failed.\n");
}
// v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
// &dev->i2c_adap[dev->def_i2c_bus],
// "saa7115_auto", 0, saa711x_addrs);
}
ログはこうなった
em28xx: v4l2_init: Attempting to probe SAA711X decoder (expected addr 0x25 or 0x24)...
em28xx: v4l2_init: SAA711X probe failed.
0x25
や 0x24
を見ているのは、I2C通信時のデバイスアドレスが7bitだかららしい。
/* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */
static unsigned short saa711x_addrs[] = {
0x4a >> 1, 0x48 >> 1, /* SAA7111, SAA7111A and SAA7113 */
0x42 >> 1, 0x40 >> 1, /* SAA7114, SAA7115 and SAA7118 */
I2C_CLIENT_END };
で、0x4a >> 1
は 0x25
に、0x48 >> 1
は 0x24
になる。
試しに8bit→7bit変換無しでそのまま0x41
を入れてみるも変化なし。
I2Cの仕様に精通していないだけに、決定的な勘違いをしている気がする。
ChatGPTもGeminiも .i2c_dev[]
の再構成が必要と言うが、そんな記載は見つけられず…。カーネルバージョン差なのかハルシネーションなのかイマイチ判別も付かず。だれか助けて。
メモ
- USBキャプチャは「認識された」だけじゃ終わらない。中の構成部品まで繋がって初めて完成
-
dmesg
,media-ctl
,i2cdump
の三種の神器でひたすら地道に追う
おわりに
USBキャプチャをRaspberry Piで動かそうとすると、気軽に始めたつもりがいつの間にか泥沼のカーネル沼に沈んでいた──そんな体験でした。
とはいえ、今後同じようなことで悩む人にとって、この記事が「ここまでやったぞ」「ここで詰まったぞ」という道標になれば嬉しいです。
続報があれば追記します。
以上、PC-SDVD/U2との奮闘記でした。