Consolidated technical reference for the Genpix SkyWalker-1 DVB-S USB 2.0 satellite receiver, derived from Linux kernel driver analysis, firmware reverse engineering (Ghidra), and Windows BDA driver source review.
---
## 1. Overview
The Genpix SkyWalker-1 is a standalone USB 2.0 DVB-S satellite receiver built around two ICs:
The FX2 handles USB communication, LNB control, DiSEqC signaling, and orchestrates tuning via I2C commands to the BCM4500. The BCM4500 performs RF demodulation, FEC decoding, and outputs an MPEG-2 transport stream on an 8-bit parallel bus. The GPIF engine inside the FX2 transfers the transport stream directly into a USB bulk endpoint with zero firmware intervention in the data path.
### Supported Modulations
| Index | Modulation | Constant |
|-------|-----------|----------|
| 0 | DVB-S QPSK | `ADV_MOD_DVB_QPSK` |
| 1 | Turbo-coded QPSK | `ADV_MOD_TURBO_QPSK` |
| 2 | Turbo-coded 8PSK | `ADV_MOD_TURBO_8PSK` |
| 3 | Turbo-coded 16QAM | `ADV_MOD_TURBO_16QAM` |
| 4 | Digicipher II Combo | `ADV_MOD_DCII_C_QPSK` |
| 5 | Digicipher II I-stream (split) | `ADV_MOD_DCII_I_QPSK` |
| 6 | Digicipher II Q-stream (split) | `ADV_MOD_DCII_Q_QPSK` |
| 7 | Digicipher II Offset QPSK | `ADV_MOD_DCII_C_OQPSK` |
| 8 | DSS QPSK | `ADV_MOD_DSS_QPSK` |
| 9 | DVB-S BPSK | `ADV_MOD_DVB_BPSK` |
DVB-S2 is **not** supported (incompatible FEC architecture).
### RF Specifications
| Parameter | Value |
|-----------|-------|
| IF frequency range | 950 -- 2150 MHz |
| Symbol rate | 256 Ksps -- 30 Msps |
| Input connector | IEC F-type female |
| LNB voltage | 13/18V (or 14/19V with USE_EXTRA_VOLT) |
| LNB current | 450 mA continuous / 750 mA burst |
| Switch control | 22 kHz, Tone Burst, DiSEqC 1.0/1.2, Legacy Dish Network |
The SkyWalker-1 (PID 0x0203) enumerates directly as a "warm" device. The DVB-USB framework skips firmware download when `cold_ids` is NULL. No host-side firmware files (`dvb-usb-gp8psk-01.fw` or `dvb-usb-gp8psk-02.fw`) are required. These files were never open-sourced or included in the `linux-firmware` package.
The vendor command dispatcher at CODE:0056 validates `bRequest` in the range 0x80--0x9D (30 entries) and dispatches via an indexed jump table at CODE:0076. Rev.2 supports only 0x80--0x9A (27 entries).
| Cmd | Name | Dir | wValue | wIndex | wLength | Purpose | Linux | Windows | v2.06 | Rev.2 | v2.13 |
| 0x9C | DELAY_COMMAND | OUT | delay | 0 | 0 | Host-controlled tuning delay + poll | No | No | STALL | N/A | OK |
| 0x9D | CW3K_INIT / SET_MODE_FLAG | OUT | 0/1 | 0 | 0 | CW3K init or conditional demod reset | Yes** | No | OK | N/A | Changed |
\* Linux driver only sends LOAD_BCM4500 for Rev.1 Warm (PID 0x0201). On SkyWalker-1, `bm8pskFW_Loaded` is already set and 0x88 routes to STALL.
\*\* Linux driver only sends CW3K_INIT for SkyWalker CW3K (PID 0x0206).
**Status key**: OK = implemented, STALL = routes to stall handler (endpoint stall returned), Proto = partial/prototype implementation, N/A = command index out of range (Rev.2 only supports 0x80--0x9A), Changed = implementation differs between versions.
### 3.2 Detailed Parameter Formats
**0x8D SEND_DISEQC_COMMAND**: When `wLength > 0`, the payload is a standard DiSEqC message (3--6 bytes) with `wValue` set to `msg[0]` (framing byte, typically 0xE0 or 0xE1). When `wLength == 0` and `wValue == 0`, a tone burst A is sent. When `wLength == 0` and `wValue != 0`, a tone burst B is sent.
**0x8F SET_DN_SWITCH**: `wValue` carries a 7-bit Dish Network switch command (LSB-first), bit-banged on GPIO P0.4 with specific timing. The 8th bit of the original switch command selects LNB voltage and is sent separately via SET_LNB_VOLTAGE.
**0x92 GET_FW_VERS**: Returns 6 bytes: `[minor_minor, minor, major, day, month, year-2000]`. Full version = `major<<16 | minor<<8 | minor_minor`. Build date = `(2000+year)/month/day`.
**0x93 GET_SERIAL_NUMBER**: Returns 4 bytes read from I2C EEPROM at device address 0x51 (7-bit), extracted at 8-bit intervals using a shift/rotate routine.
**0x94 USE_EXTRA_VOLT**: `wValue=1` writes 0x6A to XRAM 0xE0B6; `wValue=0` writes 0x62. The difference is bit 3 (0x08), which controls the extra voltage boost on the LNB power regulator.
**0x95 GET_FPGA_VERS**: Reads from I2C EEPROM at 0x51. Despite the name, there is no FPGA -- this returns the EEPROM-stored hardware platform ID. v2.06 reads offset 0x31 (2 bytes); v2.13/Rev.2 read offset 0x00 (1 byte).
**0x96--0x98**: Internal debug commands for LNB GPIO control. 0x96 configures output enables (OEB/OEA), 0x97 writes pin states, 0x98 reads a feedback pin. GPIO assignments differ between v2.06/v2.13 (Port B) and Rev.2 (Port A + Port B). See Section 10 for pin details.
---
## 4. Configuration Status Byte
Returned by GET_8PSK_CONFIG (0x80). Stored in IRAM at version-dependent addresses.
```
Bit 7 (0x80): bmArmed - MPEG-2 stream transfer armed / GPIF active
Bit 6 (0x40): bmDCtuned - DC offset tuning complete (set for DCII modes)
Bit 5 (0x20): bmSEL18V - 18V LNB voltage selected (else 13V)
Bit 4 (0x10): bm22kHz - 22 kHz tone active
Bit 3 (0x08): bmDVBmode - DVB mode enabled
Bit 2 (0x04): bmIntersilOn - LNB power supply enabled
Bit 1 (0x02): bm8pskFW_Loaded - BCM4500 firmware loaded (always set on SkyWalker-1)
Bit 0 (0x01): bm8pskStarted - Device booted and running
```
| Version | IRAM Address |
|---------|-------------|
| v2.06 | 0x6D |
| Rev.2 v2.10.4 | 0x4E |
| v2.13 | 0x4F |
---
## 5. Boot Sequence
### 5.1 Two-Stage Firmware Architecture
The FX2 supports two firmware sources:
1.**Host RAM upload** (Rev.1 Cold only): The host writes 8051 code to FX2 RAM via USB 0xA0 vendor requests, using the built-in boot ROM. This requires `dvb-usb-gp8psk-01.fw` in binary hexline format.
2.**EEPROM boot** (Rev.2, SkyWalker-1, CW3K): The FX2 boot ROM reads firmware from an external I2C EEPROM in Cypress C2 format on power-up. No host interaction needed.
### 5.2 C2 EEPROM Format
SkyWalker-1 firmware is stored in Cypress C2 IIC second-stage boot format:
=== Phase 5: Signal Acquisition (host polling) ===
14. GET_SIGNAL_LOCK (0x90) -- poll until non-zero
15. GET_SIGNAL_STRENGTH (0x87) -- read SNR
```
### 6.5 Signal Lock (GET_SIGNAL_LOCK, 0x90)
Returns 1 byte from BCM4500 register 0xA4. Bit 5 (0x20) indicates signal lock. Both the Linux and Windows drivers interpret any non-zero value as locked and report full lock status (`FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER`).
### 6.6 Signal Strength (GET_SIGNAL_STRENGTH, 0x87)
Returns 6 bytes. The first two bytes contain a 16-bit SNR value (little-endian, in dBu * 256 units):
**SNR scaling formula** (from Windows BDA driver):
```
snr_raw = (buf[1] <<8)|buf[0]
if snr_raw <= 0x0F00:
signal_strength = snr_raw * 17 // maps to 0--65535
else:
signal_strength = 0xFFFF // 100% at SNR >= 0x0F00
```
The firmware performs a multi-step I2C transaction to read signal quality: BCM4500 indirect register write/read via 0xA6/0xA7/0xA8, with read-back verification.
Version differences:
- v2.06: polls 3 registers (0xA2, 0xA8, 0xA4), loops up to 6 times
- v2.13: simplified polling (consolidated to 1 register), different call chain
| 0xF9 | Demod status (read by v2.13 GET_DEMOD_STATUS / INT0 polling) |
### 7.4 Demod Scan
The tune function tries up to 3 different I2C address configurations per attempt, with 3 outer retries (total: up to 9 I2C programming attempts). This supports hardware variants where the BCM4500 may appear at different bus addresses.
The demod scan function (Rev.2 FUN_CODE_1dd0) iterates through parameter sets computed from the iteration index (address offsets multiplied by 0x11), calling the indirect write function (FUN_CODE_1670) for each.
v2.13 adds a more sophisticated probe at boot: INT0 polls addresses 0x7F and 0x3F up to 40 times (0x28), setting a "no demod found" flag (`_1_4`) if neither responds. This flag prevents tuning attempts on boards with absent or failed demodulators.
---
## 8. GPIF Streaming Path
### 8.1 Data Flow
```
BCM4500 Cypress FX2 (CY7C68013A) USB Host
Demodulator P3.5 GPIF Engine EP2 FIFO EP2 (0x82)
(I2C:0x10) <-----> (Master Read) (AUTOIN) ------------> Bulk IN
8-bit 0xE4xx wfm 4x buffer 7 URBs
parallel 8-bit x 8KB
```
The path is fully hardware-managed. The GPIF engine reads data from the BCM4500's 8-bit parallel transport stream output directly into the EP2 FIFO. The AUTOIN bit causes automatic USB commit when the FIFO buffer is full. The FLOWSTATE engine automatically re-triggers GPIF transactions when buffer space becomes available. No firmware intervention occurs in the data path after initial setup.
### 8.2 Key Register Configuration
All values are identical across the three firmware versions:
6. Set P3 bits 7:5 = 1 (de-assert all BCM4500 control lines)
### 8.4 Interrupt Handling
INT4 and INT6 (GPIF/FIFO events) share a common handler that sets a software flag and clears the hardware interrupt. The main loop polls this flag, enters CPU idle mode (PCON.0) between events, and checks EP2CS for buffer availability before re-arming the GPIF.
---
## 9. LNB and DiSEqC Control
### 9.1 LNB Voltage
LNB voltage is controlled via GPIO P0.4 on all firmware versions. No I2C is involved.
| wValue | Voltage | GPIO P0.4 | Polarization |
|--------|---------|-----------|-------------|
| 0 | 13V | LOW | Vertical / Circular-Right |
| 1 | 18V | HIGH | Horizontal / Circular-Left |
**USE_EXTRA_VOLT** (0x94) enables a +1V boost (13V->14V, 18V->19V) for long cable runs, by writing to XRAM 0xE0B6 (0x62=normal, 0x6A=boosted; difference is bit 3).
### 9.2 22 kHz Tone
The 22 kHz tone is controlled via GPIO P0.3 on all firmware versions. P0.3 gates an external 22 kHz oscillator on the PCB. The firmware does not generate the 22 kHz signal directly.
| wValue | State | GPIO P0.3 | Band |
|--------|-------|-----------|------|
| 0 | OFF | LOW | Low band (9.75 GHz LO on universal LNB) |
| 1 | ON | HIGH | High band (10.6 GHz LO on universal LNB) |
### 9.3 DiSEqC Protocol
All firmware versions implement DiSEqC via Timer2-based GPIO bit-bang. The algorithm is identical across versions; only the data pin assignment differs (see Section 10).
**Timer2 configuration (identical across all versions):**
| Tick period | (65536 - 63535) / 4 MHz = 500.25 us |
**DiSEqC timing:**
| Parameter | Value |
|-----------|-------|
| Bit period | 1.5 ms (3 Timer2 ticks) |
| Byte period | 13.5 ms (9 bits: 8 data + 1 parity) |
| Tone burst | 12.5 ms (25 ticks) |
| Pre-TX settling delay | 7.5 ms (15 ticks) |
| Data '0' | 1.0 ms tone + 0.5 ms silence (2/3 duty) |
| Data '1' | 0.5 ms tone + 1.0 ms silence (1/3 duty) |
| Carrier frequency | 22 kHz (external oscillator gated by P0.3) |
**Manchester encoding** (decompiled from Rev.2 FUN_CODE_213c):
```
Each DiSEqC bit = 3 Timer2 ticks:
Tick 1: inter-bit gap (carrier OFF)
Tick 2: carrier ON via P0.3
Tick 3: if data='1', carrier OFF early; if data='0', carrier stays ON
End: carrier OFF
```
**Byte transmission**: 8 data bits MSB-first + 1 odd parity bit, each encoded as a Manchester symbol. The parity bit is '1' when the number of '1' data bits is even.
A 7-bit serial command bit-banged on GPIO P0.4 with specific timing:
1. Assert P0.4 HIGH (start pulse)
2. Delay ~32 cycles
3. De-assert P0.4
4. Delay ~8 cycles
5. Shift out 7 bits LSB-first via P0.4, with ~8 cycle delays between bits
The Linux kernel calls this via the `dishnetwork_send_legacy_command` frontend callback. The 8th bit (0x80) of the original switch command controls LNB voltage and is sent separately via SET_LNB_VOLTAGE.
---
## 10. GPIO Pin Map
### Port 0 (SFR 0x80, a.k.a. IOA)
| Pin | v2.06 | Rev.2 v2.10 | v2.13 | Notes |
|-----|-------|-------------|-------|-------|
| P0.0 | -- | LNB control (0x97) | **DiSEqC data** | DiSEqC data pin moved across versions |
| P0.1 | -- | -- | -- | |
| P0.2 | Init set | Init set (0x84) | Init set | BCM4500 control |
The carrier pin (P0.3) is the same across all versions. The data pin is used only internally by the firmware's Manchester encoding logic to control whether the carrier is cut short or held for the full bit period.
---
## 11. Firmware Versions
### 11.1 Version Table
| Firmware | Version | Build Date | PID | Functions | Binary Size | Stack Ptr |
Note: Rev.2 v2.10 targets a different product (PID 0x0202). The v2.13 family has three sub-variants (FW1/FW2/FW3) targeting different SkyWalker-1 hardware sub-revisions.
### 11.2 GET_FW_VERS (0x92) Format
Returns 6 bytes of hardcoded constants:
```
Byte 0: version minor_minor (e.g., 0x04)
Byte 1: version minor (e.g., 0x06)
Byte 2: version major (e.g., 0x02)
Byte 3: build day (e.g., 0x0D = 13)
Byte 4: build month (e.g., 0x07 = July)
Byte 5: build year - 2000 (e.g., 0x07 = 2007)
```
Full version number: `byte[2] << 16 | byte[1] << 8 | byte[0]`
Kernel constants for comparison:
```
GP8PSK_FW_REV1 = 0x020604
GP8PSK_FW_REV2 = 0x020704
```
### 11.3 Binary Comparison Matrix
Byte-level similarity (percentage of matching bytes within shared length):
| | v2.06 | v2.13.1 | v2.13.2 | v2.13.3 | Rev.2 |
|---|---|---|---|---|---|
| v2.06 | -- | 4.8% | 4.3% | 4.3% | 6.0% |
| v2.13.1 | | -- | 57.2% | 59.4% | 8.0% |
| v2.13.2 | | | -- | 83.5% | 5.8% |
| v2.13.3 | | | | -- | 5.8% |
| Rev.2 | | | | | -- |
The very low similarity between major versions (4--8%) indicates complete recompilation with different linker configurations. Functions are relocated even when logic is identical. Within the v2.13 family, FW2 and FW3 are 83.5% similar (minor hardware tuning), while FW1 differs more (57--59%, different demod interface).
- Has the most functions (107) but smallest binary (~8.7 KB) due to granular decomposition
- The INT0 repurposing was the last major architectural change between Rev.2 and v2.13
---
## 12. Internal Debug Commands
Commands 0x91 and 0x96--0x98 are not used by any driver (Linux or Windows). They appear to be manufacturing/debug interfaces.
### 0x91 I2C_ADDR_ADJUST
Increments (wValue != 0) or decrements (wValue == 0) an internal IRAM counter and returns its current value (1 byte). The counter is at IRAM 0x66 (v2.06) or IRAM 0x18 (v2.13/Rev.2). Likely used for I2C bus address or tuner register index adjustment during development.
### 0x96 SET_LNB_GPIO_MODE
Configures GPIO output enable registers for LNB voltage regulator hardware: