SkyStar 2 eXpress HD

From NURDspace
Revision as of 16:01, 13 April 2026 by Melan (talk | contribs)
Jump to navigation Jump to search
SkyStar 2 eXpress HD
SkyStar 2 eXpress HD.jpg
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.

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_FIELD bit in PDELCTRL2
  • 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

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:

  1. saa716x_adap.c — swap dvb_dmx_swfilter for dvb_dmx_swfilter_raw so the DMA data is passed raw to userspace instead of being parsed as 188-byte TS packets
  2. stv090x.c — set FRAME_MODE_FIELD=1 in PDELCTRL2 after 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 -S 0x80000000 -o capture.ts -c channels.conf "SomeTransponder"

-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: vmlinux not 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

References