Add Linux gp8psk kernel driver analysis and firmware-driver correlation
Maps all vendor USB control commands (0x80-0x9D) used by the kernel driver against firmware implementations across all 4 extracted versions. Key findings: - PID 0x0203 confirmed in kernel 6.16.5 module aliases (our device) - PID 0x0204 is a separate SkyWalker-1 hardware revision - LOAD_BCM4500 (0x88) intentionally STALLs on Rev.2/SkyWalker hardware - BCM4500 firmware loading protocol documented (64-byte chunked via EP0) - Complete boot, tuning, DiSEqC, and streaming sequences mapped
This commit is contained in:
parent
ec4bdb8493
commit
da08d1b099
280
gp8psk-driver-analysis.md
Normal file
280
gp8psk-driver-analysis.md
Normal file
@ -0,0 +1,280 @@
|
|||||||
|
# Genpix SkyWalker-1 DVB-S Linux Kernel Driver Analysis
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The Genpix GP8PSK driver is a Linux kernel DVB-USB compliant driver (found at `drivers/media/usb/dvb-usb/gp8psk.c`) that supports multiple Genpix satellite receiver models. The driver communicates with a Cypress FX2 microcontroller via USB vendor control requests to manage DVB-S satellite reception including demodulation, LNB power control, DiSEqC switching, and signal monitoring.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. VENDOR USB CONTROL COMMANDS (0x80-0x9D)
|
||||||
|
|
||||||
|
All vendor commands use USB control transfers with the following pattern:
|
||||||
|
- **USB Type**: `USB_TYPE_VENDOR` (vendor-specific request)
|
||||||
|
- **Direction**: `USB_DIR_IN` (device-to-host) or `USB_DIR_OUT` (host-to-device)
|
||||||
|
- **Timeout**: 2000ms
|
||||||
|
- **Retry Logic**: Up to 3 attempts for IN operations if partial data received
|
||||||
|
- **Data Buffer**: 80 bytes maximum (kernel driver state structure)
|
||||||
|
|
||||||
|
### Complete Vendor Command Map
|
||||||
|
|
||||||
|
| Cmd | Name | Direction | wValue | wIndex | wLength | Purpose |
|
||||||
|
|-----|------|-----------|--------|--------|---------|---------|
|
||||||
|
| 0x80 | **GET_8PSK_CONFIG** | IN | 0x0000 | 0x0000 | 1 byte | Read device configuration status byte |
|
||||||
|
| 0x81 | SET_8PSK_CONFIG | OUT | varies | 0x0000 | 0 | Set config (STALL - not implemented) |
|
||||||
|
| 0x82 | (reserved) | -- | -- | -- | -- | STALL - not used |
|
||||||
|
| 0x83 | **I2C_WRITE** | OUT | dev_addr | reg_addr | N bytes | Write to I2C device (BCM4500 demod) |
|
||||||
|
| 0x84 | **I2C_READ** | IN | dev_addr | reg_addr | N bytes | Read from I2C device (BCM4500 demod) |
|
||||||
|
| 0x85 | **ARM_TRANSFER** | OUT | onoff (0/1) | 0x0000 | 0 | Start/stop MPEG-2 stream transfer |
|
||||||
|
| 0x86 | **TUNE_8PSK** | OUT | 0x0000 | 0x0000 | 10 bytes | Set tuning parameters |
|
||||||
|
| 0x87 | **GET_SIGNAL_STRENGTH** | IN | 0x0000 | 0x0000 | 6 bytes | Read SNR (signal quality) |
|
||||||
|
| 0x88 | **LOAD_BCM4500** | OUT | 1 (start) | 0x0000 | 0 | Initiate BCM4500 firmware download |
|
||||||
|
| 0x89 | **BOOT_8PSK** | IN | onoff (0/1) | 0x0000 | 1 byte | Power on/off 8PSK demodulator |
|
||||||
|
| 0x8A | **START_INTERSIL** | IN | onoff (0/1) | 0x0000 | 1 byte | Enable/disable LNB power supply |
|
||||||
|
| 0x8B | **SET_LNB_VOLTAGE** | OUT | voltage (0/1) | 0x0000 | 0 | Set LNB to 13V (0) or 18V (1) |
|
||||||
|
| 0x8C | **SET_22KHZ_TONE** | OUT | onoff (0/1) | 0x0000 | 0 | Enable/disable 22 kHz DiSEqC tone |
|
||||||
|
| 0x8D | **SEND_DISEQC_COMMAND** | OUT | msg[0] | 0x0000 | len | Send DiSEqC message to dish switch |
|
||||||
|
| 0x8E | SET_DVB_MODE | OUT | 1 | 0x0000 | 0 | Enable DVB-S mode (STALL on some revisions) |
|
||||||
|
| 0x8F | (unknown) | -- | -- | -- | -- | Unknown/internal use |
|
||||||
|
| 0x90 | **GET_SIGNAL_LOCK** | IN | 0x0000 | 0x0000 | 1 byte | Read signal lock status bit |
|
||||||
|
| 0x91-0x98 | (internal use) | -- | -- | -- | -- | I2C/diagnostic reads |
|
||||||
|
| 0x99 | **GET_DEMOD_STATUS** (v2.13+) | IN | 0x0000 | 0x0000 | 1 byte | Read BCM4500 register 0xF9 via I2C |
|
||||||
|
| 0x9A | **INIT_DEMOD** (v2.13+) | OUT | 0x0000 | 0x0000 | 0 | Trigger demodulator re-init (up to 3 attempts) |
|
||||||
|
| 0x9B | (reserved) | -- | -- | -- | -- | STALL - not used |
|
||||||
|
| 0x9C | **DELAY_COMMAND** (v2.13+) | OUT | delay_param | 0x0000 | 0 | Perform tuning/acquisition delay with polling |
|
||||||
|
| 0x9D | **CW3K_INIT** | OUT | onoff (0/1) | 0x0000 | 0 | Initialize SkyWalker CW3K model |
|
||||||
|
|
||||||
|
### Configuration Status Byte (GET_8PSK_CONFIG - 0x80)
|
||||||
|
|
||||||
|
The returned byte is a bit-mapped status register:
|
||||||
|
|
||||||
|
```
|
||||||
|
Bit 0 (0x01): bm8pskStarted - Device booted and running
|
||||||
|
Bit 1 (0x02): bm8pskFW_Loaded - BCM4500 firmware loaded
|
||||||
|
Bit 2 (0x04): bmIntersilOn - LNB power supply enabled
|
||||||
|
Bit 3 (0x08): bmDVBmode - DVB mode enabled
|
||||||
|
Bit 4 (0x10): bm22kHz - 22 kHz tone active
|
||||||
|
Bit 5 (0x20): bmSEL18V - 18V LNB voltage selected (else 13V)
|
||||||
|
Bit 6 (0x40): bmDCtuned - DC offset tuning complete
|
||||||
|
Bit 7 (0x80): bmArmed - MPEG-2 stream transfer armed
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. FIRMWARE LOADING SEQUENCE
|
||||||
|
|
||||||
|
### Two-Stage Firmware Loading
|
||||||
|
|
||||||
|
The device requires **two separate firmware files**:
|
||||||
|
|
||||||
|
#### Stage 1: FX2 RAM Code (Bootloader Phase)
|
||||||
|
- **File**: `dvb-usb-gp8psk-01.fw`
|
||||||
|
- **Purpose**: Cypress FX2 microcontroller firmware
|
||||||
|
- **When**: Loaded automatically by DVB-USB framework during device enumeration (cold-to-warm boot transition)
|
||||||
|
- **How**: Standard USB firmware upload via control endpoint (0xA0 vendor request to CPUCS)
|
||||||
|
- **Device Mode**: Cold boot (VID 0x09C0, PID 0x0200)
|
||||||
|
|
||||||
|
#### Stage 2: BCM4500 Demodulator Firmware (Tuner Phase)
|
||||||
|
- **File**: `dvb-usb-gp8psk-02.fw`
|
||||||
|
- **Purpose**: Broadcom BCM4500 DVB-S demodulator chip firmware
|
||||||
|
- **When**: Loaded after device power-on via LOAD_BCM4500 command
|
||||||
|
- **How**: Custom binary protocol via USB control transfers
|
||||||
|
- **Conditions**: Only for Rev.1 Warm devices; Rev.2 and SkyWalker have firmware burned in ROM
|
||||||
|
|
||||||
|
### BCM4500 Firmware Loading Protocol
|
||||||
|
|
||||||
|
```c
|
||||||
|
// Step 1: Initiate load
|
||||||
|
gp8psk_usb_out_op(device, LOAD_BCM4500, 1, 0, NULL, 0); // 0x88 cmd, wValue=1
|
||||||
|
|
||||||
|
// Step 2: Download firmware chunks
|
||||||
|
// Format: [chunk_length] [data...] repeated, terminated by 0xFF
|
||||||
|
ptr = fw_data;
|
||||||
|
while (ptr[0] != 0xFF) {
|
||||||
|
chunk_size = ptr[0] + 4; // length byte + 3 extra bytes
|
||||||
|
if (chunk_size > 64) ERROR("chunk too large");
|
||||||
|
buf = copy chunk_size bytes from ptr;
|
||||||
|
usb_control_msg(device, USB_SNDCTRLPIPE, 0, ..., buf, chunk_size, 2000ms);
|
||||||
|
ptr += chunk_size;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Boot Sequence Flow (Power-On)
|
||||||
|
|
||||||
|
```
|
||||||
|
1. Read device config (GET_8PSK_CONFIG - 0x80)
|
||||||
|
+-- Check bit 0: Device started?
|
||||||
|
|
||||||
|
2. If not started:
|
||||||
|
+-- Boot device (BOOT_8PSK - 0x89, wValue=1)
|
||||||
|
+-- Get firmware version (via 0x0B: FW_VERSION_READ)
|
||||||
|
|
||||||
|
3. If firmware not loaded (check bit 1):
|
||||||
|
+-- Load BCM4500 firmware (LOAD_BCM4500 - 0x88)
|
||||||
|
|
||||||
|
4. If LNB not powered (check bit 2):
|
||||||
|
+-- Enable LNB supply (START_INTERSIL - 0x8A, wValue=1)
|
||||||
|
|
||||||
|
5. Set DVB mode (on some revisions):
|
||||||
|
+-- SET_DVB_MODE - 0x8E, wValue=1
|
||||||
|
|
||||||
|
6. Abort any pending MPEG transfer:
|
||||||
|
+-- ARM_TRANSFER - 0x85, wValue=0 (cancel)
|
||||||
|
|
||||||
|
7. Ready for tuning/reception
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. TUNING AND DEMODULATION FLOW
|
||||||
|
|
||||||
|
### Frequency Tuning (TUNE_8PSK - 0x86)
|
||||||
|
|
||||||
|
The tuning command transmits a 10-byte parameter structure:
|
||||||
|
|
||||||
|
```
|
||||||
|
Bytes 0-3: Symbol Rate (Little-Endian 32-bit, in sps)
|
||||||
|
Bytes 4-7: Tuner Frequency (Little-Endian 32-bit, in kHz)
|
||||||
|
Byte 8: Modulation Type (see table below)
|
||||||
|
Byte 9: Inner FEC Rate / reserved
|
||||||
|
```
|
||||||
|
|
||||||
|
### Modulation Types
|
||||||
|
|
||||||
|
```
|
||||||
|
ADV_MOD_DVB_QPSK = 0 // DVB-S standard QPSK
|
||||||
|
ADV_MOD_TURBO_QPSK = 1 // Turbo QPSK
|
||||||
|
ADV_MOD_TURBO_8PSK = 2 // Turbo 8PSK (Trellis)
|
||||||
|
ADV_MOD_TURBO_16QAM = 3 // Turbo 16QAM
|
||||||
|
ADV_MOD_DCII_C_QPSK = 4 // Digicipher II Combo
|
||||||
|
ADV_MOD_DCII_I_QPSK = 5 // Digicipher II I-stream (split)
|
||||||
|
ADV_MOD_DCII_Q_QPSK = 6 // Digicipher II Q-stream (split)
|
||||||
|
ADV_MOD_DCII_C_OQPSK = 7 // Digicipher II offset QPSK
|
||||||
|
ADV_MOD_DSS_QPSK = 8 // DSS/DIRECTV QPSK
|
||||||
|
ADV_MOD_DVB_BPSK = 9 // DVB-S BPSK
|
||||||
|
```
|
||||||
|
|
||||||
|
### Complete Tuning Sequence
|
||||||
|
|
||||||
|
```
|
||||||
|
1. Configure LNB voltage based on polarization:
|
||||||
|
H/CIRCULAR_L -> 18V (SET_LNB_VOLTAGE - 0x8B, wValue=1)
|
||||||
|
V/CIRCULAR_R -> 13V (SET_LNB_VOLTAGE - 0x8B, wValue=0)
|
||||||
|
|
||||||
|
2. Set 22 kHz tone:
|
||||||
|
SET_22KHZ_TONE - 0x8C, wValue=0/1
|
||||||
|
|
||||||
|
3. Send DiSEqC switch command if needed (see section 4)
|
||||||
|
|
||||||
|
4. Send tuning command:
|
||||||
|
TUNE_8PSK - 0x86, 10-byte parameter buffer
|
||||||
|
|
||||||
|
5. Poll for lock:
|
||||||
|
GET_SIGNAL_LOCK - 0x90 (returns 1 byte, non-zero = locked)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Signal Quality Monitoring
|
||||||
|
|
||||||
|
**GET_SIGNAL_STRENGTH (0x87)** returns 6-byte buffer:
|
||||||
|
```
|
||||||
|
Bytes 0-1: SNR value (LE 16-bit, dBu*256 units)
|
||||||
|
Bytes 2-5: Reserved/diagnostics
|
||||||
|
```
|
||||||
|
|
||||||
|
SNR scaling: `snr * 17` maps to 0-65535 (100% at SNR >= 0x0F00)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. DiSEqC COMMAND HANDLING (0x8D)
|
||||||
|
|
||||||
|
### Tone Burst (Mini DiSEqC)
|
||||||
|
```c
|
||||||
|
// For legacy 2-way switches
|
||||||
|
gp8psk_usb_out_op(device, SEND_DISEQC_COMMAND,
|
||||||
|
burst_value, // SEC_MINI_A=0x00 or SEC_MINI_B=0x01
|
||||||
|
0, NULL, 0);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Full DiSEqC Message (3-6 bytes)
|
||||||
|
```c
|
||||||
|
// Standard DiSEqC 1.0/1.1/1.2 messages
|
||||||
|
gp8psk_usb_out_op(device, SEND_DISEQC_COMMAND,
|
||||||
|
msg[0], // Framing byte as wValue
|
||||||
|
0,
|
||||||
|
msg, // Full message buffer
|
||||||
|
msg_len); // 3-6 bytes
|
||||||
|
```
|
||||||
|
|
||||||
|
Common framing bytes: 0xE0 (broadcast, no reply), 0xE1 (addressed, no reply)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. DEVICE TABLE AND USB IDS
|
||||||
|
|
||||||
|
### Kernel Module Aliases (Linux 6.16.5)
|
||||||
|
|
||||||
|
```
|
||||||
|
usb:v09C0p0200 - Rev.1 Cold boot (requires FX2 firmware upload)
|
||||||
|
usb:v09C0p0201 - Rev.1 Warm (requires BCM4500 FW via 0x88)
|
||||||
|
usb:v09C0p0202 - Rev.2 (BCM4500 in ROM)
|
||||||
|
usb:v09C0p0203 - SkyWalker-1 (PID confirmed on actual hardware)
|
||||||
|
usb:v09C0p0204 - SkyWalker-1 (alternate revision)
|
||||||
|
usb:v09C0p0206 - SkyWalker CW3K (requires CW3K_INIT 0x9D)
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: PID 0x0205 (SkyWalker-2) is absent from the 6.16.5 kernel build.
|
||||||
|
Note: PID 0x0203 was not in earlier kernel versions (e.g., v6.6.1).
|
||||||
|
|
||||||
|
### Device Properties
|
||||||
|
|
||||||
|
```c
|
||||||
|
gp8psk_properties {
|
||||||
|
usb_ctrl = CYPRESS_FX2;
|
||||||
|
firmware = "dvb-usb-gp8psk-01.fw";
|
||||||
|
num_adapters = 1;
|
||||||
|
endpoint = 0x82 (IN bulk);
|
||||||
|
stream = USB_BULK;
|
||||||
|
count = 7 URBs;
|
||||||
|
buffersize = 8192 bytes per URB;
|
||||||
|
generic_bulk_ctrl_endpoint = 0x01;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. CORRELATION: KERNEL DRIVER vs FIRMWARE ANALYSIS
|
||||||
|
|
||||||
|
### Commands Used by Kernel Driver
|
||||||
|
|
||||||
|
| Command | Driver Uses | v2.06 FW | v2.13 FW | Rev.2 FW |
|
||||||
|
|---------|-------------|----------|----------|----------|
|
||||||
|
| 0x80 GET_8PSK_CONFIG | Boot check | OK | OK | OK |
|
||||||
|
| 0x83 I2C_WRITE | BCM4500 reg writes | OK | OK | OK |
|
||||||
|
| 0x84 I2C_READ | BCM4500 reg reads | OK | OK | OK |
|
||||||
|
| 0x85 ARM_TRANSFER | Stream start/stop | OK | OK | OK |
|
||||||
|
| 0x86 TUNE_8PSK | Frequency tuning | OK | OK | OK |
|
||||||
|
| 0x87 GET_SIGNAL_STRENGTH | SNR readback | OK | Changed | OK |
|
||||||
|
| 0x88 LOAD_BCM4500 | BCM4500 FW load | **STALL** | **STALL** | **STALL** |
|
||||||
|
| 0x89 BOOT_8PSK | Power on/off | OK | OK | OK |
|
||||||
|
| 0x8A START_INTERSIL | LNB power | OK | OK | OK |
|
||||||
|
| 0x8B SET_LNB_VOLTAGE | 13V/18V | OK | OK | OK |
|
||||||
|
| 0x8C SET_22KHZ_TONE | Tone control | OK | OK | OK |
|
||||||
|
| 0x8D SEND_DISEQC | DiSEqC messages | OK (GPIO) | OK (I2C) | OK |
|
||||||
|
| 0x90 GET_SIGNAL_LOCK | Lock status | OK | OK | OK |
|
||||||
|
| 0x9D CW3K_INIT | CW3K only | N/A | v2.13 only | N/A |
|
||||||
|
|
||||||
|
### Key Finding: LOAD_BCM4500 (0x88) STALLs
|
||||||
|
|
||||||
|
Command 0x88 routes to the STALL handler in all extracted firmware versions.
|
||||||
|
The kernel driver only sends this command for Rev.1 Warm (PID 0x0201) devices,
|
||||||
|
after checking that `bm8pskFW_Loaded` (bit 1) is NOT set. On Rev.2/SkyWalker
|
||||||
|
hardware, this bit is already set at boot (BCM4500 firmware in ROM), so the
|
||||||
|
driver never attempts the load. The STALL is a safety net.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Sources
|
||||||
|
|
||||||
|
- Linux kernel 6.16.5 `dvb-usb-gp8psk` module (installed on analysis system)
|
||||||
|
- Linux kernel source: `drivers/media/usb/dvb-usb/gp8psk.c`, `gp8psk.h`, `gp8psk-fe.c`
|
||||||
|
- Windows BDA driver source: `SkyWalker1_Final_Release/Include/SkyWalker1Control.h`
|
||||||
|
- Firmware reverse engineering via Ghidra (ports 8193-8197)
|
||||||
Loading…
x
Reference in New Issue
Block a user