SkyStar 2 eXpress HD
| SkyStar 2 eXpress HD | |
|---|---|
| Participants | Melan |
| Skills | |
| Status | Active |
| Niche | Sdr |
| Purpose | |
| Tool | No |
| Location | |
| Cost | |
| Tool category | |
SkyStar 2 eXpress HD Property "Tool Image" (as page type) with input value "File:{{{Picture}}}" contains invalid characters or is incomplete and therefore can cause unexpected results during a query or annotation process. {{{Picture}}} {{#if:No | [[Tool Owner::{{{ProjectParticipants}}} | }} {{#if:No | [[Tool Cost::{{{Cost}}} | }}
Overview
This page describes the process of getting raw DVB-S2 BBframe capture working on a TechniSat SkyStar 2 eXpress HD PCIe card under Debian trixie (kernel 6.12), as part of replicating the dontlookup research project.
The dontlookup paper uses a TBS5927 USB stick with a one-line driver patch to capture raw BBframes. This write-up ports that approach to the SkyStar 2 eXpress HD, which uses a different (and more interesting) chipset.
Raspberry Pi 5
The card has been confirmed working on a Raspberry Pi 5 with a SupTronics X1010 PCIe x4 HAT. The Pi 5 exposes a PCIe Gen 2 x1 lane which is more than sufficient for a DVB card, and crucially provides 3.3V on the slot
The SkyStar requires a Molex power connector in addition to PCIe slot power. The X1010 HAT has a DC12V Molex input, providing 12V directly. A small buck converter is needed to generate the 5V rail for the Molex connector on the card (3.3V comes from the PCIe slot, 12V from the HAT Molex).
Note: The Skystar does not enumerate unless the PCIE bus is forced at gen 1 speeds with dtparam=pciex1_gen=1
lspci output on Pi 5:
0001:00:00.0 PCI bridge: Broadcom Inc. and subsidiaries BCM2712 PCIe Bridge (rev 30)
0001:01:00.0 Multimedia controller: Philips Semiconductors SAA7160 (rev 03)
0002:00:00.0 PCI bridge: Broadcom Inc. and subsidiaries BCM2712 PCIe Bridge (rev 30)
0002:01:00.0 Ethernet controller: Raspberry Pi Ltd RP1 PCIe 2.0 South Bridge
dmesg on Pi 5 (kernel 6.12.62+rpt-rpi-2712):
[ 543.603095] saa716x_core: loading out-of-tree module taints kernel.
[ 543.603753] SAA716x Budget 0001:01:00.0: found a SkyStar 2 eXpress HD PCIe card
[ 543.603770] SAA716x Budget 0001:01:00.0: enabling device (0000 -> 0002)
[ 543.603881] SAA716x Budget 0001:01:00.0: SAA7160 Rev 3, irq: 186 (MSI)
[ 543.613413] SAA716x Budget 0001:01:00.0: Initializing SAA716x I2C Core 0 @ 100kHz
[ 543.616467] SAA716x Budget 0001:01:00.0: Initializing SAA716x I2C Core 1 @ 100kHz
[ 543.619278] dvbdev: DVB: registering new adapter (SAA716x dvb adapter)
[ 543.773006] i2c i2c-15: Attaching STV6110x
[ 543.830525] SAA716x Budget 0001:01:00.0: DVB: registering adapter 0 frontend 0 (STV090x Multistandard)...
Hardware
BBframe capture has not yet been tested with an actual satellite signal. Testing pending dish access at NURDspace.
TechniSat SkyStar 2 eXpress HD
| Component | Details |
|---|---|
| PCIe bridge | NXP SAA7160 (rev 3) |
| DVB-S2 demodulator | STV0903B (STV090x family) |
| Tuner | STV6110A |
| PCI ID | Appears as Philips Semiconductors SAA7160 in lspci
|
Why This Card
The STV090x family was specifically targeted because:
- It has hardware-level BBframe support via the
FRAME_MODE_FIELDbit inPDELCTRL2 - The mainline kernel driver (
stv090x) is well maintained - The chip is well documented compared to alternatives
3.3V PCIe Issue
AMD Ryzen systems (and many modern motherboards) do not provide 3.3V on PCIe slots, as modern GPUs don't require it. DVB cards like the SkyStar 2 eXpress HD use 3.3V for their logic and will not enumerate (lspci shows nothing) on affected systems.
Workaround: Use an Intel-based system. The card was confirmed working in an X99 board. PCIe 3.3V injector risers from AliExpress are an alternative for AMD systems.
Software Environment
| Details | |
|---|---|
| OS | Debian trixie |
| Kernel | 6.12.74+deb13+1-amd64
|
| Driver source | s-moch/linux-saa716x (out-of-tree saa716x driver, maintained as kernel-version-specific diffs) |
Building the saa716x Driver
The saa716x driver is not in the mainline kernel. The s-moch repo provides diffs that patch it into the kernel source tree.
Install dependencies
sudo apt install linux-source-6.12 linux-headers-$(uname -r) \
libelf-dev build-essential flex bison libssl-dev wget
Extract kernel source and apply patch
mkdir ~/kernel-compile && cd ~/kernel-compile
wget https://github.com/s-moch/linux-saa716x/compare/saa716x-6.12.diff
tar xJf /usr/src/linux-source-6.12.tar.xz
cd linux-source-6.12
cp /boot/config-$(uname -r) .config
cp /usr/src/linux-headers-$(uname -r)/Module.symvers .
patch -p1 < ../saa716x-6.12.diff
Configure and build
make olddefconfig
make modules_prepare
make syncconfig
# Enable saa716x in config
scripts/config --enable SAA716X_SUPPORT
scripts/config --enable DVB_SAA716X_BUDGET
make syncconfig
# Build just the saa716x driver
make -C . M=drivers/media/pci/saa716x modules -j$(nproc)
Install
Extra step on Raspbian
sudo mkdir -p /lib/modules/$(uname -r)/kernel/drivers/media/pci
sudo mkdir -p /lib/modules/$(uname -r)/kernel/drivers/media/dvb-frontends
sudo cp drivers/media/pci/saa716x/saa716x_core.ko \
/lib/modules/$(uname -r)/kernel/drivers/media/pci/
sudo cp drivers/media/pci/saa716x/saa716x_budget.ko \
/lib/modules/$(uname -r)/kernel/drivers/media/pci/
sudo depmod -a
sudo modprobe saa716x_budget
Expected dmesg output
SAA716x Budget 0000:06:00.0: found a SkyStar 2 eXpress HD PCIe card
SAA716x Budget 0000:06:00.0: SAA7160 Rev 3, irq: 55 (MSI)
SAA716x Budget 0000:06:00.0: Initializing SAA716x I2C Core 0 @ 100kHz
SAA716x Budget 0000:06:00.0: Initializing SAA716x I2C Core 1 @ 100kHz
dvbdev: DVB: registering new adapter (SAA716x dvb adapter)
i2c i2c-2: Attaching STV6110x
SAA716x Budget 0000:06:00.0: DVB: registering adapter 0 frontend 0 (STV090x Multistandard)...
DVB devices appear at /dev/dvb/adapter0/{demux0,dvr0,frontend0,net0}.
BBframe Patches
Two patches are required:
saa716x_adap.c: swapdvb_dmx_swfilterfordvb_dmx_swfilter_rawso the DMA data is passed raw to userspace instead of being parsed as 188-byte TS packetsstv090x.c: setFRAME_MODE_FIELD=1inPDELCTRL2after lock, which tells the STV0903B to output raw BBframes instead of decoded TS
Background: How dontlookup's TBS5927 patch works
The original dontlookup patch for the TBS5927 is a single line added to tbs5927.c:
.caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
This flag causes the dvb-usb layer to call dvb_dmx_swfilter_raw() instead of dvb_dmx_swfilter(), passing raw bytes straight through. The saa716x patch replicates this at the PCI driver level.
Patch 1: saa716x_adap.c (Raw DMA passthrough)
File: drivers/media/pci/saa716x/saa716x_adap.c
Change dvb_dmx_swfilter to dvb_dmx_swfilter_raw in the DMA completion handler:
- dvb_dmx_swfilter(demux, data, 348 * 188);
+ dvb_dmx_swfilter_raw(demux, data, 348 * 188);
Apply with:
sed -i 's/dvb_dmx_swfilter(demux, data, 348 \* 188)/dvb_dmx_swfilter_raw(demux, data, 348 * 188)/' \
drivers/media/pci/saa716x/saa716x_adap.c
Note: The buffer size 348 * 188 = 65424 bytes is the DMA buffer size and is passed as-is. dvb_dmx_swfilter_raw does not assume 188-byte alignment so this is fine.
Patch 2: stv090x.c (Enable BBframe mode after lock)
File: drivers/media/dvb-frontends/stv090x.c
After the demodulator achieves DVB-S2 lock, set FRAME_MODE_FIELD=1 in PDELCTRL2. This tells the STV0903B to output raw BBframes rather than decoded transport stream packets.
The relevant register is defined in stv090x_reg.h:
#define STV090x_OFFST_Px_FRAME_MODE_FIELD 1
#define STV090x_WIDTH_Px_FRAME_MODE_FIELD 1
Insert the following block after the RESET_UPKO_COUNT sequence (around line 3397), immediately before the ERRCTRL1 write:
+ /* Enable BBframe mode */
+ reg = STV090x_READ_DEMOD(state, PDELCTRL2);
+ STV090x_SETFIELD_Px(reg, FRAME_MODE_FIELD, 1);
+ if (STV090x_WRITE_DEMOD(state, PDELCTRL2, reg) < 0)
+ goto err;
if (STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x67) < 0) /* PER */
Apply with Python (handles tabs correctly):
with open('drivers/media/dvb-frontends/stv090x.c', 'r') as f:
content = f.read()
old = '\t\t\t\tif (STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x67) < 0) /* PER */'
new = ('\t\t\t\t/* Enable BBframe mode */\n'
'\t\t\t\treg = STV090x_READ_DEMOD(state, PDELCTRL2);\n'
'\t\t\t\tSTV090x_SETFIELD_Px(reg, FRAME_MODE_FIELD, 1);\n'
'\t\t\t\tif (STV090x_WRITE_DEMOD(state, PDELCTRL2, reg) < 0)\n'
'\t\t\t\t\tgoto err;\n'
'\t\t\t\tif (STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x67) < 0) /* PER */')
content = content.replace(old, new, 1)
with open('drivers/media/dvb-frontends/stv090x.c', 'w') as f:
f.write(content)
Building and installing the patched modules
After applying both patches:
cd ~/kernel-compile/linux-source-6.12
# Rebuild saa716x
make -C . M=drivers/media/pci/saa716x modules -j$(nproc)
# Rebuild stv090x frontend
make -C . M=drivers/media/dvb-frontends modules -j$(nproc)
# Install
sudo cp drivers/media/pci/saa716x/saa716x_core.ko \
/lib/modules/$(uname -r)/kernel/drivers/media/pci/
sudo cp drivers/media/pci/saa716x/saa716x_budget.ko \
/lib/modules/$(uname -r)/kernel/drivers/media/pci/
sudo cp drivers/media/dvb-frontends/stv090x.ko \
/lib/modules/$(uname -r)/kernel/drivers/media/dvb-frontends/
sudo depmod -a
sudo modprobe -r saa716x_budget
sudo modprobe saa716x_budget
Capture Procedure
Once the card is connected to a dish:
1. Create a channels.conf for the target transponder
[SomeTransponder]
DELIVERY_SYSTEM = DVBS2
FREQUENCY = 1550000
SYMBOL_RATE = 30000000
POLARIZATION = HORIZONTAL
MODULATION = QPSK
INNER_FEC = AUTO
ROLLOFF = AUTO
STREAM_ID = -1
Note: frequency is the IF frequency after LNB downconversion, not the satellite frequency. For a universal LNB (LO = 9750 MHz low band / 10600 MHz high band), subtract accordingly.
2. Capture raw BBframes
dvbv5-zap -a 0 -l UNIVERSAL -S 0x80000000 -o capture.ts -c channels.conf "SomeTransponder" -m
-S 0x80000000 sets DTV_STREAM_ID to request all streams in raw mode.
3. Run dontlookup
git clone https://github.com/ucsdsysnet/dontlookup
cd dontlookup
pip install -r requirements.txt
python3 dontlookup.py capture.ts -p all
Output IP pcaps will appear in output/, open with Wireshark.
Known Issues / TODO
- Blindscan: The STV090x driver has a
stv090x_blind_search()function internally but it is never triggered from userspace. The DVB core rejects symbol rate = 0. A follow-up patch to enable blindscan via srate=0 is needed. - BTF generation skipped:
vmlinuxnot available for BTF, modules load fine but may affect BPF tooling. - BBframe capture unverified: Patches compile and load cleanly but have not yet been tested with an actual satellite signal. Testing pending dish access at NURDspace.
- Test to see if we can get this working on a Raspberry Pi 5