15 Commits
186 changed files with 4150 additions and 13021 deletions

No files matched your search

-19
View File
@@ -1,19 +0,0 @@
.git/
.gitignore
.gitattributes
.github/
output/
installer/output/
*.bin
html_data.c
html_data.h
*.o
*.rel
*.lst
*.sym
*.asm
*.ihx
*.img
*.map
*.mem
*.lk
+2 -4
View File
@@ -16,8 +16,6 @@ jobs:
- name: Install dependencies
run: |
apt update
apt install make gcc sdcc xxd python-is-python3 libjson-c-dev zlib1g-dev -y
- name: Check if machine.c can be compiled for all machines
run: make machine_check
apt install make gcc sdcc xxd python-is-python3 libjson-c-dev -y
- name: Make project
run: make MACHINE="KP_9000_6XHML_X2"
run: make MACHINE="KP_9000_6XHML_X2"
-28
View File
@@ -1,28 +0,0 @@
# Change Log
## [0.x] - 2026-xx-XX
## Added
- Web UI
- Compress the embedded assets (minify + gzip) and switch to a single-page layout. #315
## Changed
## Fixed
## Breaking changes
- Config
- VLAN don't accept port `u`-suffix anymore.
So `vlan 1 4u` is not valid anymore.
Replace it with `vlan 1 4`.
- Commands
- port zero/`0` is treated as the `CPU_PORT`. #326
- Many commands don't accept the CPU_PORT anymore. See #334.
When the CPU_PORT is needed, the command/service will add the CPU_PORT automaticly.
Only `isolate` accept the CPU_PORT as destination port.
## [v0.1_aplha] - 2025-11-03
First release.
-18
View File
@@ -1,18 +0,0 @@
FROM debian:13-slim
RUN apt-get update && apt-get install -y \
make \
gcc \
sdcc \
xxd \
python3 \
libjson-c-dev \
git \
&& rm -rf /var/lib/apt/lists/*
# git safe.directory for mounted repos (Makefile uses git describe)
RUN git config --global --add safe.directory /workspace
WORKDIR /workspace
CMD ["bash"]
+40 -123
View File
@@ -4,162 +4,79 @@ DEFAULT_CONFIG_LOCATION = 454656
CONFIG_LOCATION = 458752
HTML_LOCATION = 262144
ifeq ($(origin CC),default)
CC = sdcc
endif
CC_FLAGS = -mmcs51 -I. -Ihttpd -Iuip
ASM ?= sdas8051
ASM = sdas8051
AFLAGS= -plosgff
SUBDIRS := tools
SUBDIRS := tools uip httpd
SUBDIRSCLEAN=$(addsuffix clean,$(SUBDIRS))
BUILDDIR = output/
VERSION_HEADER := version.h
ifeq ($(MACHINE),)
MACHINE:= $(shell grep "^\s*#define MACHINE_" machine.h | sed "s/^\s*#define MACHINE_//")
else
CC_FLAGS += -DMACHINE_$(MACHINE)
endif
BUILDDIR = output/$(MACHINE)
VERSION_HEADER := version.h
GIT_VERSION := $(shell git rev-parse --short HEAD)
ifeq ($(shell git status --porcelain --untracked-files=no),)
else
GIT_VERSION := $(GIT_VERSION)-dirty
endif
VERSION_EXTENSION = v$(VERSION)-$(GIT_VERSION)
FILENAME_EXTENSION = $(VERSION_EXTENSION)-$(MACHINE)
# Deterministic build date: honor SOURCE_DATE_EPOCH, else the HEAD commit date,
# else wall-clock (no-git fallback). Keeps same-commit builds byte-identical
# (BUILD_DATE is baked into the image and covered by the trailing CRC).
SOURCE_DATE_EPOCH ?= $(shell git show -s --format=%ct HEAD 2>/dev/null)
ifeq ($(SOURCE_DATE_EPOCH),)
BUILD_DATE := $(shell date +"%Y-%m-%d %H:%M:%S")
else
BUILD_DATE := $(shell date -u -d @$(SOURCE_DATE_EPOCH) +"%Y-%m-%d %H:%M:%S" 2>/dev/null \
|| date -u -r $(SOURCE_DATE_EPOCH) +"%Y-%m-%d %H:%M:%S")
endif
all: create_build_dir $(VERSION_HEADER) $(SUBDIRS) $(BUILDDIR)/rtlplayground-$(FILENAME_EXTENSION).bin
all: create_build_dir $(VERSION_HEADER) $(SUBDIRS) $(BUILDDIR)rtlplayground.bin
create_build_dir:
mkdir -p "$(BUILDDIR)"
mkdir -p "$(BUILDDIR)/uip"
mkdir -p "$(BUILDDIR)/httpd"
mkdir -p $(BUILDDIR)
# Keep machine.c in first position to fail immediately on invalid $MACHINE value
SRCS = \
machine.c \
machine_init.c \
cmd_editor.c \
cmd_parser.c \
dhcp.c \
html_data.c \
rtlplayground.c \
boot.c \
sfp.c \
syslog.c \
udp_apps.c
SRCS = rtlplayground.c rtl837x_flash.c rtl837x_leds.c rtl837x_phy.c rtl837x_port.c cmd_parser.c html_data.c rtl837x_igmp.c \
rtl837x_stp.c rtl837x_pins.c dhcp.c machine.c cmd_editor.c rtl837x_bandwidth.c
OBJS = ${SRCS:%.c=$(BUILDDIR)%.rel}
OBJS += uip/$(BUILDDIR)/timer.rel uip/$(BUILDDIR)/uip-fw.rel uip/$(BUILDDIR)/uip-split.rel uip/$(BUILDDIR)/uip.rel uip/$(BUILDDIR)/uip_arp.rel uip/$(BUILDDIR)/uiplib.rel httpd/$(BUILDDIR)/httpd.rel httpd/$(BUILDDIR)/page_impl.rel
# RTL837x
SRCS += \
rtl837x_bandwidth.c \
rtl837x_flash.c \
rtl837x_igmp.c \
rtl837x_init.c \
rtl837x_leds.c \
rtl837x_phy.c \
rtl837x_pins.c\
rtl837x_port.c \
rtl837x_stp.c
SRCS += \
httpd/httpd.c \
httpd/page_impl.c
SRCS += \
uip/timer.c \
uip/uip.c \
uip/uiplib.c \
uip/uip_arp.c \
uip/uip-fw.c \
uip/uip-neighbor.c \
uip/uip-split.c
OBJS = ${SRCS:%.c=$(BUILDDIR)/%.rel}
DEPS := ${SRCS:%.c=$(BUILDDIR)/%.d}
HTML := $(shell find html -name '*.js' -or -name '*.html' -or -name '*.svg' -or -name '*.css' -or -name '*.ico')
# Minified copy of the web UI sources, used as the fileadder input.
# The raw html/ sources stay untouched for development; the minified
# copy is a build artifact under output/.
HTML_MIN := output/html_min
.PHONY: html_min
html_min: $(HTML)
rm -rf $(HTML_MIN)
mkdir -p $(HTML_MIN)
@for f in $(HTML); do python3 tools/minify.py $$f $(HTML_MIN)/$$(basename $$f) || exit 1; done
html_data.c html_data.h &: $(HTML) | tools html_min
tools/output/fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -b BANK1 -z -d $(HTML_MIN) -p html_data
html_data.c html_data.h: html tools
tools/$(BUILDDIR)fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -b BANK1 -d html -p html_data
$(VERSION_HEADER):
@printf '%s\n' "#ifndef VERSION_H" "#define VERSION_H" \
"#define VERSION_SW \"$(VERSION_EXTENSION)\"" \
"#define BUILD_DATE \"$(BUILD_DATE)\"" \
"#endif" > $(VERSION_HEADER)
@echo "#ifndef VERSION_H" > $(VERSION_HEADER)
@echo "#define VERSION_H" >> $(VERSION_HEADER)
@echo "#define VERSION_SW \"v$(VERSION)-g$(shell git rev-parse --short HEAD)\"" >> $(VERSION_HEADER)
@echo "#define BUILD_DATE \"$(shell date +"%Y-%m-%d %H:%M:%S")\"" >> $(VERSION_HEADER)
@echo "#endif" >> $(VERSION_HEADER)
httpd: html_data.h
$(SUBDIRS):
$(MAKE) -C $@
clean: $(SUBDIRSCLEAN)
-rm -f html_data.c html_data.h $(VERSION_HEADER)
-if [ -d $(BUILDDIR) ]; then find $(BUILDDIR) -type f ! -name "*.bin" -delete; fi
clean:
-make -C uip clean
-make -C httpd clean
-rm html_data.c html_data.h $(VERSION_HEADER)
-rm -r $(BUILDDIR)
distclean: $(SUBDIRSCLEAN)
-rm -f html_data.c html_data.h $(VERSION_HEADER)
-rm -rf $(BUILDDIR)
$(BUILDDIR)crtstart.rel: crtstart.asm
$(ASM) $(AFLAGS) -o $@ $<
$(SUBDIRSCLEAN):
$(MAKE) -C $(@:clean=) clean
$(BUILDDIR)crc16.rel: crc16.asm
$(ASM) $(AFLAGS) -o $@ $<
$(BUILDDIR)/%.rel: %.c | create_build_dir html_data.h
$(CC) -MMD $(CC_FLAGS) -o $@ -c $<
$(BUILDDIR)%.rel: %.c
$(CC) $(CC_FLAGS) -o $@ -c $<
$(BUILDDIR)/%.rel: %.asm | create_build_dir
$(BUILDDIR)%.rel: $(BUILDDIR)%.asm
${ASM} ${AFLAGS} -o $@ $<
# mv -f $(addprefix $(basename $^), .lst .rel .sym) .
$(BUILDDIR)/rtlplayground.ihx: $(OBJS) $(BUILDDIR)/crtbank.rel $(BUILDDIR)/crc16.rel
$(CC) $(CC_FLAGS) -Wl-bHOME=0x00000 -Wl-bBANK1=0x14000 -Wl-bBANK2=0x24000 -Wl-bBANK3=0x34000 -Wl-r -o $@ $^
$(BUILDDIR)rtlplayground.ihx: $(OBJS) $(BUILDDIR)crtstart.rel $(BUILDDIR)crc16.rel
$(CC) $(CC_FLAGS) -Wl-bHOME=0x00000 -Wl-bBANK1=0x14000 -Wl-bBANK2=0x24000 -Wl-r -o $@ $^
$(BUILDDIR)/rtlplayground.img: $(BUILDDIR)/rtlplayground.ihx
$(BUILDDIR)rtlplayground.img: $(BUILDDIR)rtlplayground.ihx
objcopy --input-target=ihex -O binary $< $@
$(BUILDDIR)/rtlplayground-$(FILENAME_EXTENSION).bin: $(BUILDDIR)/rtlplayground.img | tools
$(BUILDDIR)rtlplayground.bin: $(BUILDDIR)rtlplayground.img
if [ -e $@ ]; then rm $@; fi
tools/output/imagebuilder -i $^ $@
tools/output/fileadder -a $(DEFAULT_CONFIG_LOCATION) -s $(IMAGESIZE) -d config.txt $@
tools/output/fileadder -a $(CONFIG_LOCATION) -s $(IMAGESIZE) -d config.txt $@
tools/output/fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -z -d $(HTML_MIN) -p html_data -b BANK1 $@
tools/output/crc_calculator -u $@
ln -sf $(MACHINE)/rtlplayground-$(FILENAME_EXTENSION).bin output/rtlplayground.bin
tools/$(BUILDDIR)imagebuilder -i $^ $@
tools/$(BUILDDIR)fileadder -a $(DEFAULT_CONFIG_LOCATION) -s $(IMAGESIZE) -d config.txt $@
tools/$(BUILDDIR)fileadder -a $(CONFIG_LOCATION) -s $(IMAGESIZE) -d config.txt $@
tools/$(BUILDDIR)fileadder -a $(HTML_LOCATION) -s $(IMAGESIZE) -d html -p html_data $@
tools/$(BUILDDIR)crc_calculator -u $@
.PHONY: clean distclean all $(SUBDIRS) $(SUBDIRSCLEAN) $(VERSION_HEADER) create_build_dir
.PHONY:
machine_check:
@mkdir -p $(BUILDDIR)/tmp
@set -eo pipefail; \
for MACHINE in `grep -E '^[[:space:]]*(//[[:space:]]*)?#define MACHINE_' machine.h | sed -E 's%^[[:space:]]*(//[[:space:]]*)?#define MACHINE_%%' | awk '{print $$1}' | sort -u`; \
do \
echo "Checking $${MACHINE}"; \
$(CC) $(CC_FLAGS) -DMACHINE_$${MACHINE} -MMD -o $(BUILDDIR)/tmp/machine_check -c machine.c; \
$(CC) $(CC_FLAGS) -DMACHINE_$${MACHINE} -MMD -o $(BUILDDIR)/tmp/machine_check -c machine_init.c; \
done
@rm -rf $(BUILDDIR)/tmp
-include $(DEPS)
.PHONY: clean all $(SUBDIRS)
+58 -186
View File
@@ -28,10 +28,8 @@ only the following features are provided:
<img width="1420" height="623" alt="GUI" src="doc/images/gui.png" />
While the firmware provides already considerable improvements over the original managed firmware,
the firmware still lacks support for the proprietary loop prevention
protocols as well as DHCP. Spanning Tree is available (see doc/stp.md), but is
a simplified implementation - read that document before enabling it on a
switch you administer over the network. If you need these features, do not install the playground on your managed
the firmware still lacks support for STP and the proprietary loop prevention
protocols as well as DHCP. If you need these features, do not install the playground on your managed
devices. In any case, installation is strongly discouraged unless you can at least make
a backup of the original flash content via a SOIC clamp such as also used for BIOS
backups and can re-install that firmware in case something is wrong. For this no soldering
@@ -54,192 +52,88 @@ devices by looking at the image using e.g. Ghidra. If you want to contribute to
design of the web-interface or get a feeling for the interface first, a standalone
device simulator is provided, which runs entirely under Linux as a local webserver.
## (0) Compiling Requirements
## Compiling
Install the following particular build requisites (Debian 12/13), note that Ubuntu 24.04
still has an older version of sdcc, but you will need sdcc version 4.5 for the code to compile:
```
sudo apt install make gcc sdcc xxd python-is-python3 libjson-c-dev zlib1g-dev
sudo apt install make gcc sdcc xxd python-is-python3 libjson-c-dev
```
<details>
<summary>If using Docker (click to expand)</summary>
### Prerequisites
Install Docker for your platform:
- **Linux (Debian/Ubuntu)**: `sudo apt install docker.io` then `sudo usermod -aG docker $USER` (log out and back in)
- **Linux (other distros)**: Follow the [Docker Engine install guide](https://docs.docker.com/engine/install/)
- **Windows**: Install [Docker Desktop for Windows](https://docs.docker.com/desktop/setup/install/windows-install/)
- **macOS**: Install [Docker Desktop for Mac](https://docs.docker.com/desktop/setup/install/mac-install/)
### Usage
A Dockerfile is provided for a reproducible build environment:
```
docker build -t rtlplayground-dev .
```
Build the firmware (replace MACHINE with your target, e.g. `DEFAULT_8C_1SFP`):
```
docker run --rm -v $(pwd):/workspace rtlplayground-dev make MACHINE=DEFAULT_8C_1SFP
```
The resulting `.bin` file appears in `output/` on your host.
Build host tools only:
```
docker run --rm -v $(pwd):/workspace rtlplayground-dev make -C tools
```
Run the web-interface simulator locally:
```
docker run --rm -p 8080:8080 -v $(pwd):/workspace rtlplayground-dev \
tools/output/httpd_sim /workspace/html
```
Edit `machine.h` or `config.txt` on your host, then re-run `make` — the
source directory is mounted into the container, so changes take effect
immediately. To build for a different machine, pass `MACHINE=...`.
</details>
## (1) Compiling for direct chip flashing AND upgrading an existing RTLPlayground running device
Edit machine.h with an editor like vi or nano. Select the correct machine the firmware should build for.
> [!TIP]
> You can write configuration parameters in config.txt (see below) in order your switch to get
> straight at the first boot, a correct IP configuration.
Now, building the firmware image should work:
```
make
```
Note, that the image generated ends in .bin, not .img, in order to make IMSProg happy.
image location is stored in `RTLPlayground/output/rtlplayground_version_machine.bin`
for example
```
rtlplayground-v0.1.0-12c98ba-dirty-LIANGUO_ZX_SWTGW215AS.bin
```
> [!CAUTION]
> This image can be flashed directly to the chip OR through the firmware update/upgrade
> interface of RTLPlaygound interface
## (2) Compiling for OEM running device with management options (web upgrade)
Managed switches can be updated from the existing original firmware using a SPECIFIC upgrade image.
You first need to build the firmware for direct chip flashing : See below (1)
Then
```
cd installer
make
```
image location is stored in `RTLPlayground/installer/output/rtlplayground_oem_upgrade.bin`
> [!CAUTION]
> This image must ONLY be used for original OEM firmware web interface firmware upgrade.
> You do not need this image if you are already on RTLplayground firmware.
> Unless you go back to the original OEM firmware, you would only flash this specific firmware
> only once. Future upgrades of RTLPlayground will only need to follow (1)
example of compilation console output
Note, that the image generated ends in .bin, not .img, in order to make
IMSProg happy.
Managed switches can be updated from the existing original firmware using an upgrade image.
In the `installer`folder of the source code you will need to run `make` which will build
an image out of `rtlplayground.bin` built in the previous step:
```
RTLPlayground/installer$ make
mkdir -p output
mkdir -p output/
gcc updatebuilder.c -o output/updatebuilder
sdas8051 -plosgff -o output/crtstart.rel crtstart.asm
sdcc -mmcs51 --code-loc 0x1000 -o output/installer.rel -c installer.c
sdcc -mmcs51 -Wl-bHOME=0x1100 -Wl-r -o output/rtlinstaller.ihx output/crtstart.rel output/installer.rel
./output/updatebuilder -i output/rtlinstaller.ihx -o output/rtlplayground_oem_upgrade.bin ../output/rtlplayground.bin
cp ../output//rtlplayground.bin output/
./output//updatebuilder -i output/rtlinstaller.ihx output/rtlplayground.bin
Input file size: 524288
Bytes read: 524288
EOF
Payload sum 1 is: 0x25100
Payload sum 2 is: 0x25100
Payload sum with header is: 0x264ec
Payload sum is: 0xf8fe94
Header checksum is: 0x5a1
Payload sum 1 is: 0x29d10
Payload sum 2 is: 0x29d10
Payload sum with header is: 0x2b0fc
Payload sum is: 0xad8a75
Header checksum is: 0x4c3
```
The resulting image can be found in `RTLPlayground/installer/output/rtlplayground.bin`
> [!CAUTION]
> DO NOT UPLOAD THE UPGADE IMAGE UNLESS YOU CAN MAKE A BACKUP USING A SOIC CLAMP OF THE
> ORIGINAL FIRMWARE!
## (3) Sandbox Usage with Ghidra (optional)
## Installation
You can play with the image using ghidra or flash real Switch Hardware. For
ghidra see this information about [Ghidra images](doc/ghidra.md).
## (4) Installation through the Web interface (software way)
Managed switches (OEM firmware of RTLplaygroud firmware) can be upgraded via the web interface.
Unmanaged switch cannot be flashed this way (see 5).
Go to "Firmware update" tab, select the correct file.
> [!IMPORTANT]
> If your device already runs RTLPlayground, you must upload the binary file /RTLPlayground/output/rtlplayground_Version_Machine.bin
> If your device is OEM, you must upload the binary file /RTLPlayground/installer/outputrtlplayground_oem_upgrade.bin
ghidra see this information about [Ghidra images](ghidra.md).
> [!CAUTION]
> Check one more time that your device matches the machine type before flashing.
> Be shure you have a backup of the original firmware before diving in RTLPlaygroung.
> NOTE THAT WHILE THIS PROCEDURE HAS BEEN SUCCESSFULLY TESTED ON ALL DEVICES ABOVE,
> ABSOLUTELY NO GUARANTY CAN BE GIVEN THAT YOU WILL NOT DESTROY YOUR SWITCH,
> ANY OTHER EQUIPMENT INVOLVED OR HARM YOURSELF BY OPENING THE ELECTRONIC
> DEVICE. OPENING THE SWITCH WILL VOID ITS WARRANTY.
Finally, push the Upload File Button and you're done !
You can upload the upgrade image of managed switches via the web interface of the
original firmware just as if you were installing a firmware upgrade. However,
this is strongly discouraged, as you may brick your device, unless you can make
firmware backups via a SOIC clamp or soldered flash socket, first!
For unmanaged devices, the only way to install RTLPlayground is by flashing the
Flash memory directly.
## (5) Flashing the ROM directly (hardware way, but also only way to rescue)
You will need to open your switch to flash the image directly onto the flash chip,
which is done easiest using a SOIC-8 clip (alternatively you de-solder the
flash chip and install a SOIC adapter):
- Disconnect power from switch
- Attach the clip onto the flash chip
- Connect USB of flash programmer, the power LED on the switch will light
up, check cabling if not. Don't panic, mixing up GND and 3.3V does not
seem to destroy the switch (at leasts the on I did this to).
- Use IMSProg (flashrom should work, too) to detect the clip
- MAKE A BACKUP OF THE EXISTING FIRMWARE!
- then load the firmware into IMSProg
- and program flash
This procedure is the only way to flash unmanaged switches, if the ROM chip is large enough.
This is also the only way to unbrick your device if something went wroong.
Now you can connect a serial cable to the UART port found on all the
devices, set 8N1 @ 115200 baud and power up the switch.
> [!IMPORTANT]
> You need a SOIC-8 clip to flash the ROM chip directly onboard.
> Alternatively you can de-solder the flash chip and install a SOIC adapter).
> For flashing the chip directly, you must use the binary file /RTLPlayground/output/rtlplayground_Version_Machine.bin
The device will perform some examples and provide a minimal console, the
documentation of which can be found in the source code rtlplayground.c`.
> [!CAUTION]
> As you need to open your switch case, consider that the warranty is gone.
- Disconnect power from switch.
- Open the switch.
- Attach the clip onto the flash chip (Red line on Pin 1, Pin 1 has a point marker).
- Connect USB of flash programmer, the power LED on the switch will light up, check cabling if not.
- Don't panic, mixing up GND and 3.3V usually does not destroy the switch.
- Use IMSProg, Flashrom, or whatever Programmer to detect the chip.
- MAKE A BACKUP (DUMP) OF THE EXISTING FIRMWARE !
- ERASE THE ROM (BLANK) !
- Load the firmware into IMSProg.
- Flash is to the ROM chip.
- Disconect the clip from the ROM chip.
- You're done, ready for the first boot.
## (6) Connecting a serial interface (optional)
You can connect a serial cable to the UART port found on all the devices, set 8N1 @ 115200 baud.
## (7) Power Up
When you power up the switch, the device will perform some examples and provide a minimal console
(if wired to a serial interface), the documentation of which can be found in the source code rtlplayground.c`.
## (8) The web-interface
The web-interface can be reached under the [default 192.168.10.247](http://192.168.10.247) unless you
specified an IP adress in the config.txt before compilation.
> [!TIP]
> The default password is `1234`.
## (9) The command line
## The web-interface
The web-interface can be reached under the [default 192.168.10.247](http://192.168.10.247).
The default password is `1234`.
## The command line
The command line is very rudimentary and mostly for testing purposes.
The following is a boot-log with some examples:
```
@@ -304,6 +198,7 @@ PORT 04 1G
<MODULE INSERTED> Rate: 67 Encoding: 01
Lightron Inc. WSPXG-ES3LC-IHA 0000
> stat
CMD: stat
Port State Link TxGood TxBad RxGood RxBad
@@ -321,40 +216,17 @@ Lightron Inc. WSPXG-ES3LC-IHA 0000
CMD: sfp
Rate: 67 Encoding: 01
Lightron Inc. WSPXG-ES3LC-IHA 0000
```
## (10) Advanced configuration
You can configure more deeply the switch without the need of the console mode.
While in compilation part, you might write directly to config.txt file before making the binary firmware
```
nano config.txt
```
If you want to modify settings after the flash is done, go to the Advanced Settings tab in System Settings
<img width="1085" height="646" alt="ADVANCED SETTINGS" src="doc/images/advanced_settings.png" />
```
ip xxx.xxx.xxx.xxx = IP adress of the switch
gw yyy.yyy.yyy.yyy = IP adress of the gateway
netmask zzz.zzz.zzz.zzz = Network mask of the switch
port x name xxx = Name xxx the port number x
port z 1g = Set 1g speed for port z
igmp on/off = Turn IGMP on or off
```
[To be continue]
Enjoy playing!
## (11) Other documents
The following documents give further documentation on specific features of the RTL837x SoCs:
## Other documents
The following documents give further documentation on specific features of
the RTL837x SoCs:
- [RTL8372/3 Feature support](doc/hardware.md)
- [CPU Port](doc/CpuPort.md)
- [L2 learning](doc/l2.md)
- [CPU Port](doc/CpuPort.md)
- [IGMP (IP-MC streaming)](doc/igmp.md)
- [SFP+ ports](doc/sfp.md)
- [Trunking aka. port aggregation](doc/trunking.md)
-480
View File
@@ -1,480 +0,0 @@
#pragma codeseg BANK3
#pragma constseg BANK3
#include <8051.h>
#include <stdint.h>
#include <stdbool.h>
#include "rtl837x_sfr.h"
#include "rtl837x_regs.h"
#include "rtl837x_common.h"
#include "rtl837x_flash.h"
#include "rtl837x_pins.h"
#include "rtl837x_phy.h"
#include "rtl837x_port.h"
#include "rtl837x_init.h"
#include "machine.h"
#include "phy.h"
#include "boot.h"
extern __code const struct machine machine;
extern __xdata struct machine_runtime machine_detected;
extern __xdata uint8_t sfr_data[4];
extern volatile __xdata uint32_t ticks;
extern __xdata uint8_t tx_seq;
extern __code uint8_t * __code hex;
void sds_config_mac(uint8_t sds, uint8_t mode) __banked
{
reg_read_m(RTL837X_REG_SDS_MODES);
sfr_data[0] = 0;
sfr_data[1] = 0;
switch (sds) {
case 0:
sfr_mask_data(0, 0x1f, mode);
break;
case 1:
sfr_mask_data(0, 0xe0, mode << 5);
sfr_mask_data(1, 0x03, mode >> 3);
break;
case 2:
sfr_mask_data(1, 0xfc, 0x02 << 2);
}
if (machine_detected.isRTL8373) // Set 3rd SERDES Mode to 0x2 for RTL8224
sfr_mask_data(1, 0xfc, 0x02 << 2);
else
sfr_data[2] &= 0x03;
reg_write_m(RTL837X_REG_SDS_MODES);
print_string("\nRTL837X_REG_SDS_MODES: ");
print_reg(RTL837X_REG_SDS_MODES);
print_string("\n");
}
void early_boot_handle_button(void) __banked
{
if (machine.reset_pin == GPIO_NA)
return;
gpio_input_setup(machine.reset_pin);
// Debounce after init
delay(100);
// If the button is not already held at boot, continue normally.
if (gpio_pin_test(machine.reset_pin))
return;
set_sys_led_state(SYS_LED_FAST);
print_string("\n[Reset button held at boot]\n");
if (gpio_pin_test(machine.reset_pin))
return;
const __xdata uint32_t min_hold_ticks = 10UL * SYS_TICK_HZ;
const __xdata uint32_t max_hold_ticks = 30UL * SYS_TICK_HZ;
const __xdata uint32_t blink_ticks = SYS_TICK_HZ / 10; // 100 ms
const __xdata uint32_t pause_ticks = SYS_TICK_HZ / 2; // 500 ms
__xdata uint32_t start_ticks = ticks;
__xdata uint32_t last_blink_step = start_ticks;
__xdata uint8_t blink_step = 0;
set_sys_led_state(SYS_LED_ON);
while (!gpio_pin_test(machine.reset_pin)) {
__xdata uint32_t held_ticks = ticks - start_ticks;
if (held_ticks > max_hold_ticks) {
print_string("[Button held >30s at boot; continuing normal boot]\n");
return;
}
// Double blink pattern while button is held:
// ON (100ms), OFF (100ms), ON (100ms), OFF (500ms)
__xdata uint32_t step_ticks = (blink_step == 3) ? pause_ticks : blink_ticks;
if ((ticks - last_blink_step) >= step_ticks) {
blink_step = (blink_step + 1) & 0x3;
set_sys_led_state((blink_step == 0 || blink_step == 2) ? SYS_LED_ON : SYS_LED_OFF);
last_blink_step = ticks;
}
PCON |= 1;
}
set_sys_led_state(SYS_LED_ON);
if ((ticks - start_ticks) >= min_hold_ticks) {
print_string("[Button held 10s-30s at boot; restoring default config]\n");
set_sys_led_state(SYS_LED_FAST);
flash_default_config();
delay(3UL * SYS_TICK_HZ);
}
}
/*
* Configure the SerDes of the SoC for a particular mode
* to connect to an SFP module or a PHY
* Valid modes are SDS_10GR, SDS_QXGMII, SDS_HISGMII, SDS_HSG, SDS_SGMII and SDS_1000BX_FIBER
* The SerDes ID may be 0 or 1 for RTL8272 and 0-2 for RTL8373
* SDS_QXGMII is used for 10G Fiber, RTL8224 and RTL8261BE
*/
void sds_config(uint8_t sds, uint8_t mode) __banked
{
print_string("sds_config sds: "); print_byte(sds); print_string(", mode: "); print_byte(mode); write_char('\n');
sds_config_mac(sds, mode);
if (mode == SDS_10GR || mode == SDS_QXGMII)
sds_write_v(sds, 0x21, 0x10, 0x4480); // Q002110:6480
else
sds_write_v(sds, 0x21, 0x10, 0x6480); // Q002110:6480
sds_write_v(sds, 0x21, 0x13, 0x0400); // Q002113:0400
sds_write_v(sds, 0x21, 0x18, 0x6d02); // Q002118:6d02
sds_write_v(sds, 0x21, 0x1b, 0x424e); // Q00211b:424e
sds_write_v(sds, 0x21, 0x1d, 0x0002); // Q00211d:0002
sds_write_v(sds, 0x36, 0x1c, 0x1390); // Q00361c:1390
sds_write_v(sds, 0x36, 0x14, 0x003f); // Q003614:003f
uint8_t page = 0;
uint16_t v = 0;
switch (mode) {
case SDS_SGMII:
case SDS_1000BX_FIBER:
v = 0x0300;
page = 0x24;
break;
case SDS_HISGMII:
case SDS_HSG:
v = 0x0200;
page = 0x28;
break;
case SDS_10GR:
case SDS_QXGMII:
v = 0x0200;
page = 0x2e;
break;
case SDS_100FX:
v = 0x0200;
page = 0x26;
break;
default:
print_string("Error in SDS Mode\n");
return;
}
sds_write_v(sds, 0x36, 0x10, v); // Q003610:0200
if (page == 0x2e) { // 10G Fiber / SDS_QXGMII
sds_write_v(sds, page, 0x04, 0x0080); // Q012e04:0080
sds_write_v(sds, page, 0x06, 0x0408); // Q012e06:0408
sds_write_v(sds, page, 0x07, 0x020d); // Q012e07:020d
sds_write_v(sds, page, 0x09, 0x0601); // Q012e09:0601
sds_write_v(sds, page, 0x0b, 0x222c); // Q012e0b:222c
sds_write_v(sds, page, 0x0c, 0xa217); // Q012e0c:a217
sds_write_v(sds, page, 0x0d, 0xfe40); // Q012e0d:fe40
sds_write_v(sds, page, 0x15, 0xf5c1); // Q012e15:f5c1
} else {
sds_write_v(sds, page, 0x04, 0x0080); // Q002804:0080
sds_write_v(sds, page, 0x07, 0x1201); // Q002807:1201
sds_write_v(sds, page, 0x09, 0x0601); // Q002809:0601
sds_write_v(sds, page, 0x0b, 0x232c); // Q00280b:232c
sds_write_v(sds, page, 0x0c, 0x9217); // Q00280c:9217
sds_write_v(sds, page, 0x0f, 0x5b50); // Q00280f:5b50
sds_write_v(sds, page, 0x15, 0xe7c1); // Q002815:e7f1 BUG !
}
sds_write_v(sds, page, 0x16, 0x0443); // Q002816:0443 / Q012e16:0443
sds_write_v(sds, page, 0x1d, 0xabb0); // Q00281d:abb0 / Q012e1d:abb0
sds_write_v(sds, 0x06, 0x12, 0x5078); // Q000612:5078
sds_write_v(sds, 0x07, 0x06, 0x9401); // Q000706:9401
sds_write_v(sds, 0x07, 0x08, 0x9401); // Q000708:9401
sds_write_v(sds, 0x07, 0x0a, 0x9401); // Q00070a:9401
sds_write_v(sds, 0x07, 0x0c, 0x9401); // Q00070c:9401
sds_write_v(sds, 0x1f, 0x0b, 0x0003); // Q001f0b:0003
sds_write_v(sds, 0x06, 0x03, 0xc45c); // Q000603:c45c
// RTL8261BE
if (machine.n_10g && mode == SDS_QXGMII) {
sds_write_v(sds, 0x06, 0x1f, 0x2100); // Q00061f:2100
sds_write_v(sds, 0x07, 0x11, 0x054f); // Q000711:054f
sds_write_v(sds, 0x20, 0x00, 0x0030); // Q002000:0030
sds_write_v(sds, 0x20, 0x00, 0x0010); // Q002000:0010
sds_write_v(sds, 0x20, 0x00, 0x0050); // Q002000:0050
sds_write_v(sds, 0x20, 0x00, 0x00d0); // Q002000:00d0
sds_write_v(sds, 0x20, 0x00, 0x0cd0); // Q002000:0cd0
sds_write_v(sds, 0x20, 0x00, 0x04d0); // Q002000:04d0
sds_write_v(sds, 0x20, 0x00, 0x04d0); // Q002000:04d0
sds_write_v(sds, 0x20, 0x00, 0x0cd0); // Q002000:0cd0
sds_write_v(sds, 0x20, 0x00, 0x00d0); // Q002000:00d0
sds_write_v(sds, 0x20, 0x00, 0x00d0); // Q002000:00d0
sds_write_v(sds, 0x20, 0x00, 0x0050); // Q002000:0050
sds_write_v(sds, 0x20, 0x00, 0x0010); // Q002000:0010
sds_write_v(sds, 0x20, 0x00, 0x0010); // Q002000:0010
sds_write_v(sds, 0x20, 0x00, 0x0030); // Q002000:0030
sds_write_v(sds, 0x20, 0x00, 0x0000); // Q002000:0000
sds_write_v(sds, 0x1f, 0x00, 0x000b); // Q001f00:000b
sds_write_v(sds, 0x1f, 0x00, 0x0000); // Q001f00:0000
return;
}
if (mode != SDS_QXGMII)
sds_write_v(sds, 0x06, 0x1f, 0x2100); // Q00061f:2100
if (mode == SDS_1000BX_FIBER) {
sds_write_v(sds, 0x02, 0x04, 0x0020); // Q000204:0020
sds_write_v(sds, 0x00, 0x02, 0x73d0); // Q000002:73d0
sds_write_v(sds, 0x00, 0x04, 0x074d); // Q000004:074d
sds_write_v(sds, 0x20, 0x04, 0x0000); // Q002000:0000
sds_write_v(sds, 0x1f, 0x00, 0x0000); // Q001f00:0000
}
}
void rtl8224_enable(void) __banked
{
// Set Pin 4 low
reg_bit_clear(RTL837X_REG_GPIO_32_63_OUTPUT, 4);
// Configure Pin as output
reg_bit_set(RTL837X_REG_GPIO_32_63_DIRECTION, 4);
delay(100);
// Set pin 4 high
reg_bit_set(RTL837X_REG_GPIO_32_63_OUTPUT, 4);
delay(500);
}
void nic_setup(void) __banked
{
// Enable NIC
// r6040:00000100 R6040-00001100
reg_bit_set(RTL837X_REG_HW_CONF, 0xc);
// This sets the size of the RX buffer, the filling level is in 0x7874
// R7848-000004ff
REG_SET(RTL837X_REG_NIC_RXBUFF_RX, 0x4ff);
// R7844-000007fe
REG_SET(RTL837X_REG_NIC_BUFFSIZE_TX, 0x7fe);
// Configure NIC RX to receive various types of packets
// RTL837X_REG_RX_CTRL: Set bits 24-31 to 0x4, clear bits 16/17
reg_read_m(RTL837X_REG_RX_CTRL);
sfr_mask_data(3, 0xff, 0x04);
sfr_mask_data(2, 0x03, 0);
reg_write_m(RTL837X_REG_RX_CTRL);
// Enable NIC TX (set bit 0)
reg_bit_set(RTL837X_REG_TX_CTRL, 0);
// Enable NIC RX (set bit 0)
reg_bit_set(RTL837X_REG_RX_CTRL, 0);
// Drop packets with invalid CRC
reg_bit_clear(RTL837X_REG_RX_CTRL, 2);
// R603c-00000200
// CPU-port is CPU-Tag aware (bit 9)
REG_SET(RTL837X_REG_CPU_TAG_AWARE_PMASK, 0x200);
// Insert CPU-tag for internally received packets (bit 0), MODE is 0, i.e. ALL packets (bits 8-9)
reg_read_m(RTL837X_REG_CPU_TAG);
sfr_mask_data(0, 1, 1);
sfr_mask_data(1, 3, 0);
reg_write_m(RTL837X_REG_CPU_TAG);
// Force MAC mode of the CPU port (port 9)
// r6368:00000194 R6368-00000197
reg_read_m(RTL837X_REG_MAC_FORCE_MODE + 9 * 4);
sfr_mask_data(0, 0, 3); // Set bits 0, 1: Force link
reg_write_m(RTL837X_REG_MAC_FORCE_MODE+ 9 * 4);
// Sequence number of TX packets
tx_seq = 0;
}
void rtl8373_revision(void) __banked
{
reg_read_m(RTL837X_REG_CHIP_INFO);
sfr_mask_data(2, 0x0a, 0x0a); // Enable reading version
reg_write_m(RTL837X_REG_CHIP_INFO);
delay(50);
reg_read_m(RTL837X_REG_CHIP_INFO);
print_string("CPU revision: "); print_byte(sfr_data[2]); print_byte(sfr_data[2]); write_char('\n');
sfr_mask_data(2, 0x0a, 0x00); // Enable reading version
reg_write_m(RTL837X_REG_CHIP_INFO);
}
/*
* The SoC manages Link-State for steering the LEDs and can set PHY-settings
* automatically through Realtek's SMI (Simple Managagement) Interface, a
* proprietary version of MDIO which for example allows for more PHYs on the same
* bus.
* Configure polling via SMI and the interface setup during boot.
*/
void init_smi(void) __banked
{
print_string("\ninit_switch called\n");
/* Set the SMI(i.e.I2C) type for PHY polling, 0b01 is 2.5/10G PHY. Disable (0b00) for the SFP-ports
* which are at port 8 and additionally at port 3 for a dual SFP device
*/
// Default: 0x00005555
// Workaround for SDCC BUG 4070: SFR_DATA_U32 = 0x00005555;
SFR_DATA_U16_UPPER = 0x0000;
SFR_DATA_U16 = 0x5555;
if (machine.n_10g == 2) {
// 0x00015555, only change the bytes that differs from the default.
SFR_DATA_16 = 0x01;
} else if (machine.n_sfp == 2)
// 0x00005515
SFR_DATA_0 = 0x15;
reg_write(RTL837X_REG_SMI_MAC_TYPE);
// Configure polling of all PHYs by the MAC to detect link-state changes
// Default: 0x000000ff
// Workaround for SDCC BUG 4070: SFR_DATA_U32 = 0x000000ff;
SFR_DATA_U16_UPPER = 0x0000;
SFR_DATA_U16 = 0x00ff;
if (!machine_detected.isRTL8373) {
if (machine.n_sfp == 2) {
// 0x000000f0, only change the bytes that differs from the default.
SFR_DATA_0 = 0xf0;
} else {
// 0x000001f8, only change the bytes that differs from the default.
SFR_DATA_8 = 0x01;
SFR_DATA_0 = 0xf8;
}
}
reg_write(RTL837X_REG_SMI_PORT_POLLING);
// Enable MDC
reg_read_m(RTL837X_REG_SMI_CTRL);
sfr_mask_data(1, 0, 0x70); // Set bits 12-14 to enable MDC for SMI0-SMI2
reg_write_m(RTL837X_REG_SMI_CTRL);
delay(50);
if (!machine_detected.isRTL8373) {
// Change I2C addresses for SMI of the non-existent PHYs
// r6450:000020e6 R6450-000000e6
reg_read_m(RTL837X_REG_SMI_PORT6_9_ADDR);
sfr_mask_data(1, 0x7c, 0);
reg_write_m(RTL837X_REG_SMI_PORT6_9_ADDR);
// r644c:0a418820 R644c-0a400820
reg_read_m(RTL837X_REG_SMI_PORT0_5_ADDR);
sfr_mask_data(2, 0x0f, 0);
sfr_mask_data(1, 0x80, 0);
reg_write_m(RTL837X_REG_SMI_PORT0_5_ADDR);
}
if (machine.n_10g == 2) {
// Set address of second external PHY on port 8
REG_SET(RTL837X_REG_SMI_PORT6_9_ADDR, 0x000040e6);
}
}
void setup_i2c(void) __banked
{
REG_SET(RTL837X_REG_I2C_MST_IF_CTRL, 0);
// Configure SFP EEPROM address (0x50) as I2C device address
// Configure SFP readings address (0x51) as I2C device address
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16), 0x50 >> 5, (0x50 << 3) & 0xff);
REG_SET(RTL837X_REG_I2C_CTRL2, 0);
// HW Control register, enable I2C depending on PIN configuration
reg_read_m(RTL837X_PIN_MUX_1);
for (uint8_t sfp = 0; sfp < machine.n_sfp; sfp++) {
const uint8_t scl_bus = i2c_bus_from_scl_pin(machine.sfp_port[sfp].i2c.scl);
const uint8_t sda_bus = i2c_bus_from_sda_pin(machine.sfp_port[sfp].i2c.sda);
print_string("Configuring I2C for SFP idx="); print_byte(sfp); print_string(" SCL="); print_byte(scl_bus); print_string(", SDA="); print_byte(sda_bus); write_char('\n');
switch (scl_bus) {
case 3:
// Bit 5-6 0b10 -> SCL (implies enabled SDA on bus 3)
sfr_mask_data(0, 0x60, 0x40);
break;
case 2:
// Bit 15-16 0b01 -> SCL
sfr_mask_data(1, 0x80, 0x80);
sfr_mask_data(2, 0x01, 0x00);
break;
case 1:
// Bit 11-12 0b01 -> SCL
sfr_mask_data(1, 0x18, 0x08);
break;
case 0:
// Bit 7-8 0b01 -> SCL
sfr_mask_data(0, 0x80, 0x80);
sfr_mask_data(1, 0x01, 0x00);
break;
default:
print_string("Invalid SCL bus number: "); print_byte(scl_bus); write_char('\n');
}
switch (sda_bus) {
case 4:
// Bit 29 0b0 -> SDA
sfr_mask_data(3, 0x20, 0x00);
break;
case 3:
// Bit 5-6 0b10 -> SDA (implies enabled SCL on bus 3)
sfr_mask_data(0, 0x60, 0x40);
break;
case 2:
// Bit 17-18 0b01 -> SDA
sfr_mask_data(2, 0x06, 0x02);
break;
case 1:
// Bit 13-14 0b01 -> SDA
sfr_mask_data(1, 0x60, 0x20);
break;
case 0:
// Bit 9-10 0b01 -> SDA
sfr_mask_data(1, 0x06, 0x02);
break;
default:
print_string("Invalid SDA bus number: "); print_byte(sda_bus); write_char('\n');
}
}
reg_write_m(RTL837X_PIN_MUX_1);
}
/* Give the switch a name carrying the tail of its MAC, so several of them on
* one network are distinguishable out of the box. Called after the startup
* config has been replayed and returns at once if that config already set a
* name, so a configured switch does no work for it (suggested in review).
*
* Written without a loop on purpose. Locals - counters and pointers alike -
* land in the 8051's internal-RAM overlay, and on an image with LACP and STP
* both enabled that overlay is exhausted: a loop here makes the linker fail
* with "Could not get 8 consecutive bytes in internal RAM for area OSEG".
* Moving the code into its own function does not help; the overlay is shared
* across the whole image. Hoisting the locals to xdata does not help either,
* because itohex() is inline and brings its own frame. */
void set_hostname_default(void) __banked
{
if (hostname[0] != NUL)
return;
strcpy((__xdata uint8_t *)hostname, "RTLPlayground-");
hostname[14] = hex[uip_ethaddr.addr[3] >> 4];
hostname[15] = hex[uip_ethaddr.addr[3] & 0xf];
hostname[16] = hex[uip_ethaddr.addr[4] >> 4];
hostname[17] = hex[uip_ethaddr.addr[4] & 0xf];
hostname[18] = hex[uip_ethaddr.addr[5] >> 4];
hostname[19] = hex[uip_ethaddr.addr[5] & 0xf];
hostname[20] = NUL;
}
-14
View File
@@ -1,14 +0,0 @@
#ifndef BOOT_H
#define BOOT_H
void sds_config_mac(uint8_t sds, uint8_t mode) __banked;
void sds_config(uint8_t sds, uint8_t mode) __banked;
void early_boot_handle_button(void) __banked;
void rtl8224_enable(void) __banked;
void nic_setup(void) __banked;
void rtl8373_revision(void) __banked;
void init_smi(void) __banked;
void setup_i2c(void) __banked;
void set_hostname_default(void) __banked;
#endif
+18 -21
View File
@@ -40,24 +40,21 @@ void cmd_edit(void) __banked
{
while (l != sbuf_ptr) {
if (sbuf[l] >= ' ' && sbuf[l] < 127) { // A printable character, copy to command line
// Reserve one byte for the terminating NUL written on Enter. When the
// line is full, drop the character but still fall through to advance the
// serial-ring read pointer below; a 'continue' here would spin forever.
if (cmd_line_len < CMD_BUF_SIZE - 1) {
write_char(sbuf[l]);
// Shift buffer to right
for (uint8_t i = cmd_line_len; i > cursor; i--)
cmd_buffer[i] = cmd_buffer[i-1];
// Insert char in comand buffer
cmd_buffer[cursor++] = sbuf[l];
cmd_line_len++;
// Print rest of line
for (uint8_t i = cursor; i < cmd_line_len; i++)
write_char(cmd_buffer[i]);
// Move backwards
for (uint8_t i = cursor; i < cmd_line_len; i++)
write_char('\010'); // BS works like cursor-left
}
if (cmd_line_len >= CMD_BUF_SIZE)
continue;
write_char(sbuf[l]);
// Shift buffer to right
for (uint8_t i = cmd_line_len; i > cursor; i--)
cmd_buffer[i] = cmd_buffer[i-1];
// Insert char in comand buffer
cmd_buffer[cursor++] = sbuf[l];
cmd_line_len++;
// Print rest of line
for (uint8_t i = cursor; i < cmd_line_len; i++)
write_char(cmd_buffer[i]);
// Move backwards
for (uint8_t i = cursor; i < cmd_line_len; i++)
write_char('\010'); // BS works like cursor-left
} else if (sbuf[l] == '\033') { // ESC-Sequence
// Wait until we have at least 3 characters including the ESC character in the serial buffer
if (((sbuf_ptr + SBUF_SIZE - l) & SBUF_MASK) < 3)
@@ -172,7 +169,7 @@ void cmd_edit(void) __banked
} else { // An unknown or not yet complete Escape sequence: wait
continue;
}
} else if (sbuf[l] == 127 || sbuf[l] == 8) { // Backspace DEL or BS/^H
} else if (sbuf[l] == 127) { // Backspace
if (cursor > 0) {
write_char('\010');
for (uint8_t i = cursor; i < cmd_line_len; i++)
@@ -193,14 +190,14 @@ void cmd_edit(void) __banked
// Check whether return was pressed:
if (sbuf[l] == '\n' || sbuf[l] == '\r') {
write_char('\n');
cmd_buffer[cmd_line_len] = NUL;
cmd_buffer[cmd_line_len] = '\0';
// write_char('>'); print_string_x(cmd_buffer); write_char('<');
// If there is a command we print the prompt after execution
// otherwise immediately because there is nothing to execute
if (cmd_line_len)
cmd_available = 1;
else
print_cmd_prompt();
print_string("\n> ");
cursor = 0;
cmd_line_len = 0;
history_editptr = 0xffff;
+403 -1291
View File
File diff suppressed because it is too large. Load diff
+1 -6
View File
@@ -7,15 +7,10 @@
extern __xdata uint8_t cmd_buffer[CMD_BUF_SIZE];
extern __xdata uint8_t cmd_available;
extern __xdata uint8_t err_status;
void cmd_tokenize(void) __banked;
uint8_t cmd_tokenize(void) __banked;
void cmd_parser(void) __banked;
void execute_config(void) __banked;
void execute_commands(__xdata uint8_t *p) __banked;
void print_ip(__xdata uint8_t *ptr) __banked;
void print_mac(__xdata uint8_t *ptr) __banked;
void print_sw_version(void) __banked;
void clear_command_history(void) __banked;
#endif
+1 -7
View File
@@ -3,8 +3,6 @@
;
.globl _crc_value
.globl _crc16
.globl _crc16_bank1
.globl __sdcc_banked_ret
.equ BANK, 0x96
; .equ DPS, 0x86
; Variable in XMEM holding current CRC16 value, being updated
@@ -20,7 +18,7 @@ _crc_value::
.area HOME (CODE)
.area CSEG (CODE)
; .area BANK1 (CODE)
_crc16_bank1:
_crc16:
mov BANK, #1
push dph
push dpl
@@ -54,10 +52,6 @@ _crc16_bank1:
.area BANK1 (CODE)
_crc16:
lcall _crc16_bank1
ljmp __sdcc_banked_ret
crc16_table_l:
.byte #0x00, #0xc1, #0x81, #0x40, #0x01, #0xc0, #0x80, #0x41
.byte #0x01, #0xc0, #0x80, #0x41, #0x00, #0xc1, #0x81, #0x40
-29
View File
@@ -1,29 +0,0 @@
.area HOME (CODE)
.area GSINIT0 (CODE)
.area GSINIT1 (CODE)
.area GSINIT2 (CODE)
.area GSINIT3 (CODE)
.area GSINIT4 (CODE)
.area GSINIT5 (CODE)
.area GSINIT (CODE)
.area GSFINAL (CODE)
.area CSEG (CODE)
.area HOME (CODE)
__sdcc_banked_call::
push _PSBANK
xch a,r0
push a
mov a,r1
push a
mov a,r2
anl a,#0x1f
mov _PSBANK, a
xch a, r0
ret
__sdcc_banked_ret::
pop _PSBANK
ret
+17
View File
@@ -0,0 +1,17 @@
.area GSFINAL (CODE)
__sdcc_banked_call::
push _PSBANK
xch a,r0
push a
mov a,r1
push a
mov a,r2
anl a,#0x1f
mov _PSBANK, a
xch a, r0
ret
__sdcc_banked_ret::
pop _PSBANK
ret
+272 -62
View File
@@ -15,6 +15,9 @@
__xdata struct dhcp_state dhcp_state;
__xdata uip_ipaddr_t server;
#define BOOTP_REQUEST 1
#define BOOTP_REPY 2
#define DHCP_HW_TYPE_ETH 1
#define DHCP_SUBNET_MASK 1
@@ -32,6 +35,7 @@ __xdata uip_ipaddr_t server;
#define DHCP_MESSAGE_DISCOVER 1
#define DHCP_MESSAGE_OFFER 2
#define DHCP_MESSAGE_REQUEST 3
#define DHCP_MESSAGE_NACK 4
#define DHCP_MESSAGE_ACK 5
#define DHCP_LEASE 51
#define DHCP_LEASE_LEN 4
@@ -41,18 +45,25 @@ __xdata uip_ipaddr_t server;
#define DHCP_REBIND_LEN 4
#define DHCP_CLIENT_ID 61
#define DHCP_CLIENT_ID_LEN 7
#define DHCP_HOSTNAME 12
#define DHCP_REQUEST_IP 50
#define DHCP_REQUEST_IP_LEN 4
#define DHCP_CLIENT_NAME 12
#define DHCP_PARAMS 55
#define DHCP_VENDOR_ID 60
#define DHCP_CLIENT_ID 61
#define DHCP_PARAM_SUBNET 1
#define DHCP_PARAM_ROUTER 3
#define DHCP_PARAM_DNS 6
#define DHCP_END 255
#define LEASE_TIME 43200
#define RENEWAL_TIME 21600
#define REBIND_TIME 21600
#pragma codeseg BANK2
#pragma constseg BANK2
struct dhcp_pkt {
uint8_t type;
uint8_t hw;
@@ -76,9 +87,11 @@ struct dhcp_pkt {
#define DHCP_OPT ((__xdata uint8_t *)(uip_appdata) + sizeof (struct dhcp_pkt))
__xdata uint32_t long_value;
__xdata struct dhcpd_cstate cstates[DHCPD_MAX_CLIENTS];
__xdata uint8_t client_idx;
__xdata uint16_t dhcpd_vlan;
void dhcp_print_ip(__xdata uint8_t *a)
void dhcp_print_ip(uint8_t *a)
{
itoa(a[0]); write_char('.');
itoa(a[1]); write_char('.');
@@ -87,14 +100,14 @@ void dhcp_print_ip(__xdata uint8_t *a)
}
void dhcp_prepare_request(void)
void dhcp_prepare_msg(void)
{
DHCP_P->type = 1;
DHCP_P->type = BOOTP_REQUEST;
DHCP_P->hw = DHCP_HW_TYPE_ETH;
DHCP_P->hw_len = 6;
DHCP_P->hops = 0;
DHCP_P->tid = dhcp_state.transaction_id;
DHCP_P->tid = dhcp_state.transaction_id; // In network byte order
DHCP_P->delay = HTONS(0);
DHCP_P->flags = 0;
// Clear fields client_ip to bootp_file
@@ -117,20 +130,6 @@ void dhcp_addopt_client_id(void)
}
void dhcp_addopt_hostname(void)
{
uint8_t len = 0;
while (hostname[len])
len++;
if (!len)
return;
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_HOSTNAME;
DHCP_OPT[dhcp_state.opt_ptr++] = len;
memcpy(&DHCP_OPT[dhcp_state.opt_ptr], hostname, len);
dhcp_state.opt_ptr += len;
}
void dhcp_addopt_request_ip(void)
{
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_REQUEST_IP;
@@ -139,7 +138,6 @@ void dhcp_addopt_request_ip(void)
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.current_ip[1];
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.current_ip[2];
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.current_ip[3];
memcpy(&DHCP_OPT[dhcp_state.opt_ptr], uip_ethaddr.addr, 4);
}
@@ -151,14 +149,68 @@ void dhcp_addopt_server_id(void)
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.server[1];
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.server[2];
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.server[3];
memcpy(&DHCP_OPT[dhcp_state.opt_ptr], uip_ethaddr.addr, 4);
}
void dhcp_addopt_subnet(void)
{
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_SUBNET_MASK;
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_SUBNET_MASK_LEN;
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.subnet[0];
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.subnet[1];
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.subnet[2];
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.subnet[3];
}
void dhcp_addopt_router(void)
{
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_ROUTER;
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_ROUTER_LEN;
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.router[0];
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.router[1];
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.router[2];
DHCP_OPT[dhcp_state.opt_ptr++] = dhcp_state.router[3];
}
void dhcp_addopt_lease(void)
{
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_LEASE;
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_LEASE_LEN;
DHCP_OPT[dhcp_state.opt_ptr++] = 0;
DHCP_OPT[dhcp_state.opt_ptr++] = 0;
DHCP_OPT[dhcp_state.opt_ptr++] = LEASE_TIME >> 8;
DHCP_OPT[dhcp_state.opt_ptr++] = LEASE_TIME & 0xff;
}
void dhcp_addopt_renewal(void)
{
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_RENEWAL;
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_RENEWAL_LEN;
DHCP_OPT[dhcp_state.opt_ptr++] = 0;
DHCP_OPT[dhcp_state.opt_ptr++] = 0;
DHCP_OPT[dhcp_state.opt_ptr++] = RENEWAL_TIME >> 8;
DHCP_OPT[dhcp_state.opt_ptr++] = RENEWAL_TIME & 0xff;
}
void dhcp_addopt_rebind(void)
{
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_REBIND;
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_REBIND_LEN;
DHCP_OPT[dhcp_state.opt_ptr++] = 0;
DHCP_OPT[dhcp_state.opt_ptr++] = 0;
DHCP_OPT[dhcp_state.opt_ptr++] = REBIND_TIME >> 8;
DHCP_OPT[dhcp_state.opt_ptr++] = REBIND_TIME & 0xff;
}
void dhcp_send_discover(void)
{
print_string("dhcp_send_discover called\n");
dhcp_prepare_request();
dhcp_prepare_msg();
dhcp_state.opt_ptr = 0;
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_MESSAGE_TYPE;
@@ -167,7 +219,6 @@ void dhcp_send_discover(void)
dhcp_addopt_client_id();
dhcp_addopt_request_ip();
dhcp_addopt_hostname();
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_PARAMS;
DHCP_OPT[dhcp_state.opt_ptr++] = 3;
@@ -194,7 +245,7 @@ void dhcp_send_discover(void)
void dhcp_send_request(void)
{
print_string("dhcp_send_request called\n");
dhcp_prepare_request();
dhcp_prepare_msg();
dhcp_state.opt_ptr = 0;
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_MESSAGE_TYPE;
@@ -204,7 +255,6 @@ void dhcp_send_request(void)
dhcp_addopt_client_id();
dhcp_addopt_request_ip();
dhcp_addopt_server_id();
dhcp_addopt_hostname();
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_PARAMS;
DHCP_OPT[dhcp_state.opt_ptr++] = 3;
@@ -228,7 +278,42 @@ void dhcp_send_request(void)
}
void ip_opt(__xdata uint8_t * ip)
void dhcp_send_reply(uint8_t rtype)
{
print_string("dhcp_send_reply called\n");
dhcp_prepare_msg();
DHCP_P->type = BOOTP_REPY;
DHCP_P->client_addr[0] = cstates[client_idx].mac[0]; DHCP_P->client_addr[1] = cstates[client_idx].mac[1];
DHCP_P->client_addr[2] = cstates[client_idx].mac[2]; DHCP_P->client_addr[3] = cstates[client_idx].mac[3];
DHCP_P->client_addr[4] = cstates[client_idx].mac[4]; DHCP_P->client_addr[5] = cstates[client_idx].mac[5];
if (rtype != DHCP_MESSAGE_NACK) {
DHCP_P->your_ip[0] = dhcp_state.server[0];
DHCP_P->your_ip[1] = dhcp_state.server[1];
DHCP_P->your_ip[2] = dhcp_state.server[2];
DHCP_P->your_ip[3] = DHCPD_START_IP + client_idx;
}
dhcp_state.opt_ptr = 0;
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_MESSAGE_TYPE;
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_MESSAGE_TYPE_LEN;
DHCP_OPT[dhcp_state.opt_ptr++] = rtype;
if (rtype != DHCP_MESSAGE_NACK) {
dhcp_addopt_subnet();
dhcp_addopt_router();
dhcp_addopt_server_id();
dhcp_addopt_rebind();
dhcp_addopt_lease();
dhcp_addopt_renewal();
}
DHCP_OPT[dhcp_state.opt_ptr++] = DHCP_END;
uip_udp_send(sizeof(struct dhcp_pkt) + dhcp_state.opt_ptr);
}
void ip_opt(uint8_t * __xdata ip)
{
dhcp_state.opt_ptr++;
uint8_t len = DHCP_OPT[dhcp_state.opt_ptr++];
@@ -255,6 +340,22 @@ void long_opt(void)
}
void print_txt_opt(void)
{
dhcp_state.opt_ptr++;
for (uint8_t l = DHCP_OPT[dhcp_state.opt_ptr++]; l ; l--)
write_char(DHCP_OPT[dhcp_state.opt_ptr++]);
}
void print_eth_opt(void)
{
dhcp_state.opt_ptr++;
for (uint8_t l = DHCP_OPT[dhcp_state.opt_ptr++]; l ; l--)
print_byte(DHCP_OPT[dhcp_state.opt_ptr++]);
}
void parse_opts(void)
{
while (DHCP_OPT[dhcp_state.opt_ptr] && DHCP_OPT[dhcp_state.opt_ptr] != DHCP_END) {
@@ -274,6 +375,9 @@ void parse_opts(void)
case DHCP_BROADCAST:
ip_opt(&dhcp_state.broadcast[0]);
break;
case DHCP_REQUEST_IP:
ip_opt(&dhcp_state.current_ip[0]);
break;
case DHCP_LEASE:
long_opt();
dhcp_state.lease = long_value;
@@ -286,6 +390,27 @@ void parse_opts(void)
long_opt();
dhcp_state.renewal = long_value;
break;
case DHCP_CLIENT_NAME:
print_string("Client name: ");
print_txt_opt();
write_char('\n');
break;
case DHCP_VENDOR_ID:
print_string("Vendor ID: ");
print_txt_opt();
write_char('\n');
break;
case DHCP_CLIENT_ID:
print_string("Client ID: ");
print_eth_opt();
write_char('\n');
break;
case DHCP_PARAMS:
print_string("PARAMS request (ignored)\n");
dhcp_state.opt_ptr++;
dhcp_state.opt_ptr += DHCP_OPT[dhcp_state.opt_ptr];
dhcp_state.opt_ptr++;
break;
case DHCP_END:
break;
default:
@@ -298,9 +423,39 @@ void parse_opts(void)
}
void parse_dhcp(void)
void find_client(void)
{
if (DHCP_P->tid != dhcp_state.transaction_id)
uint8_t i;
for (i = 0; i < DHCPD_MAX_CLIENTS; i++) {
if (cstates[i].mac[0] == DHCP_P->client_addr[0] && cstates[i].mac[1] == DHCP_P->client_addr[1]
&& cstates[i].mac[2] == DHCP_P->client_addr[2] && cstates[i].mac[3] == DHCP_P->client_addr[3]
&& cstates[i].mac[4] == DHCP_P->client_addr[4] && cstates[i].mac[5] == DHCP_P->client_addr[5]
)
break;
}
if (i < DHCPD_MAX_CLIENTS) {
client_idx = i;
return;
}
client_idx = 255;
}
void find_slot(void)
{
for (client_idx = 0; client_idx < DHCPD_MAX_CLIENTS; client_idx++) {
if (!cstates[client_idx].cstate)
return;
}
client_idx = 255;
return;
}
void parse_dhcp_response(void)
{
if (!DHCP_P->tid == dhcp_state.transaction_id)
return;
if (DHCP_P->cookie[0] != 0x63 || DHCP_P->cookie[1] != 0x82 || DHCP_P->cookie[2] != 0x53 || DHCP_P->cookie[3] != 0x63)
return;
@@ -332,18 +487,6 @@ void parse_dhcp(void)
uip_ipaddr(&uip_hostaddr, dhcp_state.current_ip[0], dhcp_state.current_ip[1], dhcp_state.current_ip[2], dhcp_state.current_ip[3]);
uip_ipaddr(&uip_draddr, dhcp_state.router[0], dhcp_state.router[1], dhcp_state.router[2], dhcp_state.router[3]);
uip_ipaddr(&uip_netmask, dhcp_state.subnet[0], dhcp_state.subnet[1], dhcp_state.subnet[2], dhcp_state.subnet[3]);
/* T1 is optional. Without it the renewal time stays zero, which
* makes dhcp_timer zero, and the callback then sends a REQUEST on
* every pass through LEASING: client and server trade REQUEST and
* ACK as fast as the round trip allows. RFC 2131 has the client
* renew at half the lease when the server does not say, and if
* there is no lease either, pick something rather than zero. Only
* filled in when absent, so a server that asks for a short renewal
* still gets it. */
if (!dhcp_state.renewal)
dhcp_state.renewal = dhcp_state.lease / 2;
if (!dhcp_state.renewal)
dhcp_state.renewal = 60;
dhcp_state.state = DHCP_LEASING;
dhcp_state.ticks = SYS_TICK_HZ;
dhcp_state.dhcp_timer = dhcp_state.renewal > 0xffff ? 0xffff : dhcp_state.renewal;
@@ -351,35 +494,98 @@ void parse_dhcp(void)
}
void parse_dhcp_request(void)
{
print_string("parse_dhcp_request called\n");
if (DHCP_P->cookie[0] != 0x63 || DHCP_P->cookie[1] != 0x82 || DHCP_P->cookie[2] != 0x53 || DHCP_P->cookie[3] != 0x63)
return;
dhcp_state.opt_ptr = 0;
if (DHCP_OPT[dhcp_state.opt_ptr++] != DHCP_MESSAGE_TYPE || DHCP_OPT[dhcp_state.opt_ptr++] != DHCP_MESSAGE_TYPE_LEN)
return;
if (DHCP_OPT[dhcp_state.opt_ptr] == DHCP_MESSAGE_DISCOVER) {
dhcp_state.opt_ptr++;
find_client();
if (client_idx == 255)
find_slot();
// If there is no empty slot, we play possum and do not answer to the request
if (client_idx == 255)
return;
cstates[client_idx].cstate = CSTATE_OFFERED;
cstates[client_idx].mac[0] = DHCP_P->client_addr[0]; cstates[client_idx].mac[1] = DHCP_P->client_addr[1];
cstates[client_idx].mac[2] = DHCP_P->client_addr[2]; cstates[client_idx].mac[3] = DHCP_P->client_addr[3];
cstates[client_idx].mac[4] = DHCP_P->client_addr[4]; cstates[client_idx].mac[5] = DHCP_P->client_addr[5];
dhcp_state.transaction_id = DHCP_P->tid;
parse_opts();
dhcp_send_reply(DHCP_MESSAGE_OFFER);
} else if (DHCP_OPT[dhcp_state.opt_ptr++] == DHCP_MESSAGE_REQUEST) {
find_client();
if (client_idx == 255) {
dhcp_send_reply(DHCP_MESSAGE_NACK);
return;
}
parse_opts();
dhcp_send_reply(DHCP_MESSAGE_ACK);
}
}
void dhcp_start(void) __banked
{
/* Starting twice would leave the first socket bound: uip_udp_new() takes
* the next free slot while the old one keeps port 68, and dhcp_callback()
* matches on that port rather than on the connection, so every leftover
* runs the state machine too and the timers count down once per socket. */
if (dhcp_state.state != DHCP_OFF)
dhcp_stop();
uip_ipaddr(server, 255,255,255,255);
dhcp_state.conn = uip_udp_new(&server, HTONS(DHCPC_SERVER_PORT));
dhcp_state.conn = uip_udp_new(&server, HTONS(DHCP_SERVER_PORT));
dhcp_state.current_ip[0] = dhcp_state.current_ip[1] = dhcp_state.current_ip[2] = dhcp_state.current_ip[3] = 0;
if(dhcp_state.conn) {
uip_udp_bind(dhcp_state.conn, HTONS(DHCPC_CLIENT_PORT));
uip_udp_bind(dhcp_state.conn, HTONS(DHCP_CLIENT_PORT));
} else {
print_string("dhcp_start failed to set up socket\n");
return;
}
get_random_32();
// Workaround SDCC bug 4070: dhcp_state.transaction_id = SFR_DATA_U32;
__xdata uint8_t * tid = &dhcp_state.transaction_id;
*tid++ = SFR_DATA_24;
*tid++ = SFR_DATA_16;
*tid++ = SFR_DATA_8;
*tid = SFR_DATA_0;
dhcp_state.transaction_id = SFR_DATA_U32;
dhcp_state.state = DHCP_START;
print_string("dhcp_start done\n");
}
void dhcpd_start(void) __banked
{
memset(&cstates[0], 0, sizeof (struct dhcpd_cstate) * DHCPD_MAX_CLIENTS);
dhcp_state.conn = uip_udp_new(0, 0);
if(dhcp_state.conn) {
uip_udp_bind(dhcp_state.conn, HTONS(DHCP_SERVER_PORT));
} else {
print_string("dhcpd_start failed to set up socket\n");
return;
}
if (!dhcpd_vlan)
print_string("dhcpd: enabling for all VLANs\n");
else
print_string("dhcpd: enabling for VLAN "); print_short(dhcpd_vlan); write_char('\n');
dhcp_state.state = DHCP_SERVER;
dhcp_state.server[1] = uip_hostaddr[0] >> 8; dhcp_state.server[0] = uip_hostaddr[0] & 0xff;
dhcp_state.server[3] = uip_hostaddr[1] >> 8; dhcp_state.server[2] = uip_hostaddr[1] & 0xff;
dhcp_state.router[1] = uip_draddr[0] >> 8; dhcp_state.router[0] = uip_draddr[0] & 0xff;
dhcp_state.router[3] = uip_draddr[1] >> 8; dhcp_state.router[2] = uip_draddr[1] & 0xff;
dhcp_state.subnet[1] = uip_netmask[0] >> 8; dhcp_state.subnet[0] = uip_netmask[0] & 0xff;
dhcp_state.subnet[3] = uip_netmask[1] >> 8; dhcp_state.subnet[2] = uip_netmask[1] & 0xff;
dhcp_state.broadcast[0] = dhcp_state.router[0]; dhcp_state.broadcast[1] = dhcp_state.router[1];
dhcp_state.broadcast[2] = dhcp_state.router[2]; dhcp_state.broadcast[3] = 0xff;
for (uint8_t i = 0; i < DHCPD_MAX_CLIENTS; i++) {
cstates[i].cstate = CSTATE_NONE;
}
// TODO: DNS, correct broadcast address
print_string("dhcpd_start done\n");
}
void dhcp_stop(void) __banked
{
print_string("dhcp_stop called\n");
@@ -387,18 +593,25 @@ void dhcp_stop(void) __banked
dhcp_state.state = DHCP_OFF;
}
void dhcpd_stop(void) __banked
{
print_string("dhcpd_stop called\n");
uip_udp_remove(dhcp_state.conn);
dhcp_state.state = DHCP_OFF;
}
void dhcp_callback(uint16_t lport) __banked
void dhcp_callback(void) __banked
{
if (lport != HTONS(DHCPC_CLIENT_PORT)) // Is this call for us? If not, ignore it
return;
if (!dhcp_state.state)
return;
if (uip_closed()) {
print_string("Closed\n");
return;
} else if (dhcp_state.state == DHCP_SERVER && uip_newdata()) {
parse_dhcp_request();
} else if (uip_newdata()) {
parse_dhcp();
parse_dhcp_response();
} else {
if (dhcp_state.state == DHCP_START) {
dhcp_send_discover();
@@ -421,7 +634,4 @@ void dhcp_callback(uint16_t lport) __banked
}
}
}
// By default we do not send anything out
uip_len = 0;
}
+28 -6
View File
@@ -3,21 +3,26 @@
#include "uipopt.h"
#include <stdint.h>
#define DHCPD_MAX_CLIENTS 20
#define DHCPD_START_IP 100
#define DHCPC_SERVER_PORT 67
#define DHCPC_CLIENT_PORT 68
#define DHCP_SERVER_PORT 67
#define DHCP_CLIENT_PORT 68
#define DHCP_OFF 0
#define DHCP_START 1
#define DHCP_DISCOVER_SENT 2
#define DHCP_REQUEST_SENT 3
#define DHCP_LEASING 4
#define DHCP_SERVER 5
#define CSTATE_NONE 0
#define CSTATE_OFFERED 1
#define CSTATE_LEASED 2
void dhcp_start(void) __banked;
void dhcp_stop(void) __banked;
// void dhcp_periodic(void) __banked;
void dhcp_callback(uint16_t lport) __banked;
void dhcp_callback(void) __banked;
struct dhcp_state {
uint8_t state;
@@ -35,9 +40,26 @@ struct dhcp_state {
uint32_t rebind;
uint32_t renewal;
__xdata struct uip_udp_conn *conn;
struct uip_udp_conn *conn;
};
struct dhcpd_cstate {
uint8_t cstate;
uint16_t timer;
uint32_t transaction_id;
uint8_t mac[6];
uint8_t ip[4];
};
void dhcpd_start(void) __banked;
void dhcpd_stop(void) __banked;
typedef struct dhcp_state uip_udp_appstate_t;
/* Finally we define the application function to be called by uIP. */
#ifndef UIP_UDP_APPCALL
#define UIP_UDP_APPCALL dhcp_callback
#endif /* UIP_APPCALL */
#endif
-30
View File
@@ -64,33 +64,3 @@ Writing 0x1 to register 0x7850 will transmit the frame. The Ethernet frame
checksum and the TCP checksum are automatically calculated (offloaded) by the
ASIC before transmitting on the wire.
## The RTL tag words
The frame header uses the Realtek Remote Control Protocol (RRCP) format or
the like.
The `flags` word:
```
bit15 EFID_EN | 14:12 EFID | 11 PRI_EN | 10:8 PRI |
bit7 KEEP | 6 VSEL | 5 LEARN_DIS | 4:0 VIDX
```
All fields are in network byte order.
* `EFID_EN`, `EFID`: look the destination up under this filtering ID
instead of the port's own
* `PRI_EN`, `PRI`: force the given priority on the frame
* `KEEP`: keep the 802.1Q tagging of the frame exactly as injected,
bypassing the egress tagging rules of the port
* `VSEL`, `VIDX`: classify the frame into the VLAN at this index of the
VLAN table
* `LEARN_DIS`: do not learn the source address from this frame
The `pmask` word: bit 15 is `ALLOW`, bits 14 to 0 are a port mask.
* `ALLOW` clear: the mask is the egress set, the frame goes to exactly
the ports given
* `ALLOW` set: the ASIC looks the destination up as usual and the mask
only limits which ports the result may use
-32
View File
@@ -1,32 +0,0 @@
# Automation
## Upload
You can automate upload of the firmware via WEB with curl:
1. Authorize with /login endpoint and save cookie:
```bash
curl -c cookies.txt http://${SWITCH_IP}/login -d pwd=${PASSWORD} -i
```
This will save session cookie in cookies.txt
2. Send the firmware via form:
```bash
curl -b cookies.txt http://${SWITCH_IP}/upload -F "uploadedfile=@${FIRMWARE_FILE_PATH}" -i
```
You can expect that server will close connection, without responding to request.
Wait for SWITCH_IP to be responding again.
## Port status
In similar way to upload, you can fetch the json status of the ports.
1. Get the session cookie as for upload.
2. Hit the `/status.json` with cookie:
```bash
curl -b cookies.txt http://${SWITCH_IP}/status.json
```
-177
View File
@@ -1,177 +0,0 @@
### 2M-PCB23-V2.2
## Brands
| Brand | Type | Managed | PCB | Flash | Chip RTL |
|----------|-----------------|---------|---------------|-------|-------------|
| keepLINK | KP-9000-9XHML-X | Yes | 2M-PCB23-V2.2 | 2M | 8373 + 8224 |
## PCB
<img src="photos/2M-PCB23-V2.2-managed/2M-PCB23-V2.2-top.jpg" width="300" />
## Port overview
```
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ ┌──────────┐ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ SFP(J13) │ │
│ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ PORT 9 │ │
│ │ PORT 1 │ │ PORT 2 │ │ PORT 3 │ │ PORT 4 │ │ PORT 5 │ │ PORT 6 │ │ PORT 7 │ │ PORT 8 │ │ MAC 8 │ O (PWR) │
│ O │ MAC 0 │ │ MAC 1 │ │ MAC 2 │ │ MAC 3 │ │ MAC 4 │ │ MAC 5 │ │ MAC 6 │ │ MAC 7 │ │ SerDes 1 │ O (SFP) │
│ RST └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
```
# Connectors
### J13, SFP connector
| SFP Pin | Signal | GPIO | Notes |
| ------- | ----------------- | ------ | ------------------------------ |
| 2 | TX_FAULT | ?? | |
| 3 | TX_DISABLE | ?? | |
| 4 | MODDEF2 – SDA | GPIO39 | |
| 5 | MODDEF1 – SCL | GPIO40 | |
| 6 | MODDEF0 – PRESENT | GPIO30 | "OE Exist" reported by `fiber` |
| 7 | RATE SEL | ?? | |
| 8 | LOS | GPIO37 | "OE LOS" reported by `fiber` |
| 9 | TO? | ?? | |
### T5, serial console
| pin | GPIO | Signal |
| --- | ------ | -------------- |
| 1 | GPIO32 | U0RXD (Input) |
| 2 | GND | Ground |
| 3 | GPIO31 | U0TXD (Output) |
### S1, unknown connector
| pin | GPIO | Signal |
| --- | -------- | -------------- |
| 1 | ??? | |
| x | | |
| 3 | ??? | |
| 4 | ??? | |
| 5 | ??? | |
Potentially slave interface or SMI.
### U7, flash memory
Flash chip is FM25Q16A.
### Reset button
GPIO54
## Register values
As probed with `regget` on stock firmware "V1.6".
### Model
| Name | Addr | Value |
| ------------------------- | ------ | ---------- |
| MODEL_NAME_INFO | 0x0004 | 0x83730000 |
| CHIP_MODE_INFO | 0x0008 | 0x00008000 |
| CHIP_INFO | 0x000C | 0x00300000 |
### GPIO
| Name | Addr | Value |
| ------------------------- | ------ | ---------- |
| GPIO_OUT0 | 0x003c | 0x10000000 |
| GPIO_OUT1 | 0x0040 | 0x00000010 |
| GPIO_OE0 | 0x004c | 0x10000000 |
| GPIO_OE1 | 0x0050 | 0x00000010 |
| BOND_INFO | 0x7f60 | 0x00000fff |
| STRAP_INFO | 0x7f64 | 0x0002f515 |
| IO_DRVING_0 | 0x7f68 | 0x00000000 |
| IO_DRVING_1 | 0x7f6c | 0x00000000 |
| IO_DRVING_2 | 0x7f70 | 0x00000000 |
| IO_SLEW_0 | 0x7f74 | 0x00000000 |
| IO_SLEW_1 | 0x7f78 | 0x00000000 |
| IO_SLEW_2 | 0x7f7c | 0x00000000 |
| IO_SMT_EN_0 | 0x7f80 | 0xffffffff |
| IO_SMT_EN_1 | 0x7f84 | 0xffffffff |
| IO_SMT_EN_2 | 0x7f88 | 0x0003ffff |
| IO_MUX_SEL_0 | 0x7f8c | 0x28000000 |
| IO_MUX_SEL_1 | 0x7f90 | 0x40000041 |
| IO_MUX_SEL_2 | 0x7f94 | 0x00000000 |
### LED
| Name | Addr | Value |
| ------------------------- | ------ | ---------- |
| LED_GLB_CTRL | 0x6520 | 0x0023e0f0 |
| LED3_0_SET3_2_CTRL1 | 0x6524 | 0xff001400 |
| LED3_0_SET1_0_CTRL1 | 0x6528 | 0x000f0000 |
| LED3_2_SET3_CTRL0 | 0x652c | 0x007f013f |
| LED1_0_SET3_CTRL0 | 0x6530 | 0x02000400 |
| LED3_2_SET2_CTRL0 | 0x6534 | 0x01400141 |
| LED1_0_SET2_CTRL0 | 0x6538 | 0x01440170 |
| LED3_2_SET1_CTRL0 | 0x653c | 0x18000041 |
| LED1_0_SET1_CTRL0 | 0x6540 | 0x0044017f |
| LED3_2_SET0_CTRL0 | 0x6544 | 0x00000044 |
| LED1_0_SET0_CTRL0 | 0x6548 | 0x00410175 |
| LED_PORT_SET_SEL_CTRL | 0x654c | 0x00010000 |
| SW_LED_LOAD | 0x6550 | 0x00000000 |
| LED_PORT_SW_EN_CTRL[0..7] | 0x6554 | 0x00000000 |
| LED_PORT_SW_EN_CTRL[8] | 0x6558 | 0x00000000 |
| LED_PORT_SW_CTRL[0] | 0x655c | 0x00000000 |
| LED_PORT_SW_CTRL[1] | 0x6560 | 0x00000000 |
| LED_PORT_SW_CTRL[2] | 0x6564 | 0x00000000 |
| LED_PORT_SW_CTRL[3] | 0x6568 | 0x00000000 |
| LED_PORT_SW_CTRL[4] | 0x656c | 0x00000000 |
| LED_PORT_SW_CTRL[5] | 0x6570 | 0x00000000 |
| LED_PORT_SW_CTRL[6] | 0x6574 | 0x00000000 |
| LED_PORT_SW_CTRL[7] | 0x6578 | 0x00000000 |
| LED_PORT_SW_CTRL[8] | 0x657c | 0x00000000 |
| LED_LOAD_LV1_10G | 0x6580 | 0x000fa000 |
| LED_LOAD_LV2_10G | 0x6584 | 0x00271000 |
| LED_LOAD_LV3_10G | 0x6588 | 0x004e2000 |
| LED_LOAD_LV1_5G | 0x658c | 0x000fa000 |
| LED_LOAD_LV2_5G | 0x6590 | 0x00271000 |
| LED_LOAD_LV3_5G | 0x6594 | 0x004e2000 |
| LED_LOAD_LV1_2P5G | 0x6598 | 0x000fa000 |
| LED_LOAD_LV2_2P5G | 0x659c | 0x00271000 |
| LED_LOAD_LV3_2P5G | 0x65a0 | 0x004e2000 |
| LED_LOAD_LV1_1G | 0x65a4 | 0x000fa000 |
| LED_LOAD_LV2_1G | 0x65a8 | 0x00271000 |
| LED_LOAD_LV3_1G | 0x65ac | 0x004e2000 |
| LED_LOAD_LV1_500M | 0x65b0 | 0x0007d000 |
| LED_LOAD_LV2_500M | 0x65b4 | 0x00138800 |
| LED_LOAD_LV3_500M | 0x65b8 | 0x00271000 |
| LED_LOAD_LV1_100M | 0x65bc | 0x00019000 |
| LED_LOAD_LV2_100M | 0x65c0 | 0x0003e800 |
| LED_LOAD_LV3_100M | 0x65c4 | 0x0007d000 |
| LED_LOAD_LV1_10M | 0x65c8 | 0x00002800 |
| LED_LOAD_LV2_10M | 0x65cc | 0x00006400 |
| LED_LOAD_LV3_10M | 0x65d0 | 0x0000c800 |
| LED_P_LOAD_CTRL | 0x65d4 | 0x00000000 |
| LED_GLB_ACTIVE | 0x65d8 | 0x3ffbedff |
| LED_GLB_IO_EN | 0x65dc | 0x77ffffff |
| LED_GLB_MUX_1 | 0c65e0 | 0x05102040 |
| LED_GLB_MUX_2 | 0x65e4 | 0x0c289206 |
| LED_GLB_MUX_3 | 0x65e8 | 0x1245038d |
| LED_GLB_MUX_4 | 0x65ec | 0x19616554 |
| LED_GLB_MUX_5 | 0x65f0 | 0x2079d71a |
| LED_GLB_MUX_6 | 0x65f4 | 0x000238a1 |
| LED_RLDP_CTRL_1 | 0x65f8 | 0x00000019 |
| LED_RLDP_CTRL_2 | 0x65fc | 0xffffffff |
| LED_RLDP_CTRL_3 | 0x6600 | 0x00006600 |
| LED_DUMY_0_ADDR | 0x6604 | 0x00000000 |
| LED_DUMY_1_ADDR | 0x6608 | 0x00000000 |
# LEDs
| Name | Components | Controlled by |
| ----------------------------- | --------------------------- | -------------------------- |
| RJ45 Right Green ("LINK/ACT") | | RJ45 LED0 |
| RJ45 Left Orange ("2.5G") | | RJ45 LED1 |
| RJ45 Left Green ("1G") | | RJ45 LED2 |
| "P" (PWR) | Top LED in "LED6" stack | probably pulled from Vcc |
| SFP Link ("9") | Bottom LED in "LED6" stack | SFP LED0 |
| ?? | D23 | SFP LED1 |
| ?? | D22 | SFP LED2 |
-55
View File
@@ -1,55 +0,0 @@
# 2G040210GSM
The following is a documentation for the managed switch marked as `2G040210GSM`
and sold by Mokerlink.
### Label specifications
- **Name**: 4-port 2.5G Web Managed Switch
- **Ports**:
- 4 × RJ45: 10/100/1000/2500 Mbps
- 2 × SFP+: 1000 / 2500 / 10000 Mbps
- **Power**: 12V DC, 1A barrel connector
### What works
The device is fully supported:
- All 4 2.5GBASE-T RJ45 ports work at 10/100/1000/2500 Mbps
- The SFP+ port supports 1G, 2.5G and 10G modules
- LEDs work with the same indiciations as the OEM firmware (use KP_9000_6XHML_X2_V1_1 in machine.h if building yourself or the corresponding pre-compiled binary)
- untested due to missing Hardware: SFP+ ports equipped with 1G or 2.5G SFPs.
### Hardware overview
Front
<img src="photos/2M-PCB43-V1.1-managed/2M-PCB43-V1.1-front.jpeg" width="300" />
Label
<img src="photos/2M-PCB43-V1.1-managed/2M-PCB43-V1.1-label.jpeg" width="300" />
### PCB overview
**Board markings**
- Top silkscreen: 2M-PCB43-V1.1
Top side
<img src="photos/2M-PCB43-V1.1-managed/2M-PCB43-V1.1-top.jpeg" width="300" />
Bottom
<img src="photos/2M-PCB43-V1.1-managed/2M-PCB43-V1.1-bottom.jpeg" width="300" />
### J1, serial console
| `J8` pin | Signal |
| -------- | ----------- |
| 1 | RX (Input) |
| 2 | TX (Output) |
| 3 | GND |
| 4 | 3V3 |
## Power supply
Input power is delivered via barell plug, `12V 1A` adapter was provided.
-32
View File
@@ -1,32 +0,0 @@
# MokerLink POE-2G080110GS
The `POE-2G080110GS` is an unmanaged 8x2.5G RJ45 and 1xSFP+ PoE switch sold by Mokerlink. There is also a `POE-2G080110GSM` managed version of the switch which may be similar but this has not been verified on actual hardware.
## Brands
| Brand | Type |Managed| PCB | Flash | Chip RTL |
|--------|------------------|-------|------------------|-----------------|---------------|
| Mokerlink | POE-2G080110GS | No | 2M-PCB51-ML-V1.1 | 4MB (W25Q32JV) | 8373N + 8224N |
## Hardware overview
Front
<img src="photos/POE-2G080110GS/POE-2G080110GS-front.jpg" width="300" />
Label
<img src="photos/POE-2G080110GS/POE-2G080110GS-label.jpg" width="300" />
The stock firmware from a POE-2G080110GS device had a sha256sum of `4c280853465eaad80e1772075c0f2d29c11fb8c561547f06353d3a5443c388e9`.
### PCB
Top silkscreen is marked `2M-PCB51-ML-V1.1`. PoE is provided by RTL8238C. Flash chip is 4 MB Winbond 25Q32JV (U8).
<img src="photos/POE-2G080110GS/POE-2G080110GS-pcb.jpg" width="300" />
> [!CAUTION]
> This device operates on mains voltage, which can be a dangerous or potentially lethal hazard. Even after the device is unplugged, high-voltage capacitors can remain charged afterward and may still shock you. Do not attempt to open/disassemble a mains powered device unless you understand how to do so safely. Also, opening the device may void your warranty.
## Notes
The stock firmware blinks both the 2.5G and 1G LEDs on activity, despite the front of the device indicating that each LED should be independent. The `POE_2G080110GS` machine config behaves as the front of the device indicates (and what seems more logical) -- each port LED turns on and blinks independently.
-39
View File
@@ -1,39 +0,0 @@
# FG-4GT-2SX_V2.0
Following is documentation for unmanaged switch marked as `FG-4GT-2SX_V2.0`.
Original software is running UART on 9600 baud rate.
## Brands
* Ruiying RY-4GT-2SX
<img src="photos/FG-4GT-2SX_V2.0/RY-4GT-2SX_label.jpg" width="300" />
## What works
- All four 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
- Both SFP ports supporting 1G, 2.5G and 10G modules
- LEDs
## PCB overview
**Board markings**
- Top silkscreen: FG-4GT-2SX_V2.0
Front panel
<img src="photos/FG-4GT-2SX_V2.0/chassis-front.jpg" width="300" />
Top side
<img src="photos/FG-4GT-2SX_V2.0/PCB-top.jpg" width="300" />
Bottom
<img src="photos/FG-4GT-2SX_V2.0/PCB-bottom.jpg" width="300" />
## Power supply
Input power is delivered via barell plug, `12V 1A` adapter was provided.
-79
View File
@@ -1,79 +0,0 @@
# FG-8GT-1SX
Following is documentation for unmanaged switch marked as `FG-8GT-1SX`.
Original software is running UART on 9600 baud rate.
Using SPI clamp in-board is the only method for initial installation.
### Brands
| Brand | Type | Managed | PCB | Flash | Chip RTL |
|---------|------------|---------|------------|-------------|---------------|
| Ruiying | RY-8GT-1SX | No | FG-8GT-1SX | GD25Q80ESIG | 8373N + 8224N |
### What works
- All eight 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
- SFP port with 1G/2.5G/10G modules
- LEDs
### PCB overview
**Board markings**
- Top silkscreen: FG-8GT-1SX
Top side:
<img src="photos/FG-8GT-1SX/PCB-top.jpg" width="600" />
Bottom:
<img src="photos/FG-8GT-1SX/PCB-bottom.jpg" width="600" />
### Serial console
The PCB has five unpopulated through-holes near the SoC, with a white rectangle surrouding them, labeled as `J18` and a triangle points to the square shaped first pin.
This is where the "expected" UART header should be soldered at, with redundant 3V3 VCC, but also with missing 0Ω resistors between TX/RX and SoC, so simply soldering a header would not work. One need also add the missing resistors or solder the pads together, while making sure not connecting unrelated pads.
Numbered from the triangle, the header pinout is:
| Position | Signal | GPIO | Status |
|----------|--------|--------|-------------|
| 1 | GND | GND | Internal |
| 2 | TX | GPIO31 | Unconnected |
| 3 | RX | GPIO32 | Unconnected |
| 4 | 3V3 | - | Internal |
| 5 | 3V3 | - | Internal |
There're four resistor pads near the header.
| Resistor ID | SoC Side | Header Side |
|-------------|-------------|-------------|
| R1240 | TX / GPIO31 | Pin 2 |
| R1243 | 3V3 | - |
| R1242 | 3V3 | Pin 3 |
| R1241 | RX / GPIO32 | - |
To get TX working, solder a 0Ω resistor between the pads for R1240 or solder them together.
For RX However, the designer certainly made a mistake, as the SoC-side lines to the resistor expected for Rx (R1242) and 3V3 (R1241) are swapped. For RX to work, the R1241 SoC side and R1242 header side shall be connected, so either:
- Solder: R1241 SoC side -> R1241 header side -> R1242 header side
- Jump wire: R1241 SoC side -> R1242 header side
Be sure not to bring R1242 SoC side to the connection as that would wire Rx to 3v3.
A complete working serial header should look like following on this PCB:
<img src="photos/FG-8GT-1SX/Serial.png" width="600" />
- **Settings**: 115200 baud / 8N1 / 3.3V TTL
- Connect a USB-TTL adapter: adapter GND → pin 1, RX → pin 2, TX → pin 3
### Power supply
Input power is delivered via barell plug, `12V 1A` adapter was provided.
-93
View File
@@ -1,93 +0,0 @@
# FOXNEO FNS-1200P
RTL8372-based 4×2.5G PoE+ + 2×SFP+ unmanaged switch.
Using SPI clamp in-board is the only method for initial installation.
### Label specifications
- **Manufacturer**: FOXNEO
- **Model**: FNS-1200P
- **Ports**:
- 4 × RJ45: 10/100/1000/2500 Mbps with PoE+
- 2 × SFP+: 1G / 2.5G / 10G
### What works
- All four 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps (PoE+ is not configurable via RTLPlayground)
- Both SFP+ ports supporting 1G, 2.5G and 10G modules
- LEDs: amber (2.5G) and green (1G/100M/10M) per copper port; combined link/act on SFP ports
### PCB overview
**Board markings**
- Top silkscreen: PCB-K0402W-U13-V2.0 / DIP-K0402WB-V2.0
**Key components**
- U3: SPI NOR flash, 2 MiB
- U7: unpopulated SOP8 footprint — I2C bus (RTL8372 slave at 0x5c) is accessible from its pads, useful for register dumps
- S1: unpopulated slide switch footprint (three through-holes used as serial console)
Front panel
<img src="photos/FNS-1200P/chassis-front.jpg" width="400" />
Top side (PCB)
<img src="photos/FNS-1200P/PCB-top.jpg" width="300" />
### Port layout
| Front panel position | Logical port | Physical port | Type |
|----------------------|--------------|---------------|---------|
| SFP left | 8 | 5 | SFP+ |
| RJ45 1 | 4 | 1 | Copper |
| RJ45 2 | 5 | 2 | Copper |
| RJ45 3 | 6 | 3 | Copper |
| RJ45 4 | 7 | 4 | Copper |
| SFP right | 3 | 6 | SFP+ |
### Serial console
The PCB has three unpopulated through-holes intended for a slide switch, directly connected to UART0.
Numbered from the left (SFP port side), the pinout is:
| Position (left→right) | Signal | GPIO |
|-----------------------|--------|--------------------------|
| 1 (leftmost) | RX | GPIO32\_UART0\_RX (32) |
| 2 (middle) | GND | GND |
| 3 (rightmost) | TX | GPIO31\_UART0\_TX (31) |
- **Settings**: 115200 baud / 8N1 / 3.3V TTL
- Connect a USB-TTL adapter: adapter TX → pin 1, GND → pin 2, adapter RX → pin 3
### LED configuration
Copper ports use LED SET0, SFP ports use LED SET1.
| SET | LED0 | LED2 |
|------|--------------------------------------------------|---------------------------------------------------|
| SET0 | Amber — lights on 2.5G link | Green — lights on 1G / 100M / 10M link |
| SET1 | All speeds — lights on any link with activity | — |
LED pad to physical port mapping:
| GPIO pads | Port |
|-----------|-------------------------|
| GPIO8–11 | Physical port 5 (left SFP) |
| GPIO12–14 | Physical port 1 (RJ45 1) |
| GPIO15–17 | Physical port 2 (RJ45 2) |
| GPIO18–20 | Physical port 3 (RJ45 3) |
| GPIO21–23 | Physical port 4 (RJ45 4) |
| GPIO24–27 | Physical port 6 (right SFP) |
### SFP GPIO assignments
| SFP | pin\_detect (ModAbs) | pin\_los | SerDes | I2C SDA | I2C SCL |
|------------------|-----------------------------|------------------------|--------|----------------------|--------------------------|
| Left (logical 8) | GPIO30\_ACL\_BIT3\_EN | GPIO37 | SDS1 | GPIO39\_I2C\_SDA4 | GPIO40\_I2C\_SCL3\_MDC1 |
| Right (logical 3)| GPIO50\_I2C\_SCL2\_UART1\_TX | GPIO51\_I2C\_SDA2\_UART1\_RX | SDS0 | GPIO41\_I2C\_SDA3\_MDIO1 | GPIO40\_I2C\_SCL3\_MDC1 |
GPIO assignments were verified by observing GPIO state changes during SFP module insertion/removal
and cross-checked against an original firmware register dump.
`pin_tx_disable` is GPIO\_NA on both ports (original firmware keeps all GPIOs as inputs).
+62
View File
@@ -0,0 +1,62 @@
# Hisource Hi-K0402WS
Following is documentation for unmanaged switch marked as `Hi-K0402WS`.
Original software is running UART on 9600 baud rate.
Using SPI clamp in-board is the only method for initial installation.
The board has two flash chips `BY25Q16BS` with 16M-bit size. The front switch, switches between the two flash chips.
These can be programed independently by using said switch - so it is e.g. possible to run the original and new firmware in parallel.
### Label specifications
- **Name**: 2.5G Ethernet Switch
- **Model**: Hi-K0402WS
- **Ports**:
- 4 × RJ45: 10/100/1000/2500 Mbps
- 2 × SFP: 1000 / 2500 / 10000 Mbps
### What works (expected from label + similar devices)
- All four 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
- Both SFP ports supporting 1G, 2.5G and 10G modules
- LEDs
### PCB overview
**Board markings**
- Top silkscreen: PCB-KO4022W-V3.0 / DIP-KO4022WS-V3.0
Top side
<img src="photos/K0402W-V3.0-unmanaged\PCB-top.jpg" width="300" />
Bottom
<img src="photos/K0402W-V3.0-unmanaged\PCB-bottom.jpg" width="300" />
### T2, serial console
| `J2` pin | Signal |
| -------- | ----------- |
| 1 | 3V3 |
| 2 | RX (Input) |
| 3 | TX (Output) |
| 4 | GND |
## Power supply
Input power is delivered via barell plug, `12V 1A` adapter was provided.
Board has two supply rails. `0.95` and `3.3` volt.
### `0.95` Core Voltage
Voltage is made by a `Techcode TD1720` .
### `3.3` Voltage
Voltage is created by chip marked as `Techcode TD1720`.
**There seems to have been a miscalculation when choosing the inductor and the device is ~25% more efficient with an 5V power supply.**
-36
View File
@@ -1,36 +0,0 @@
# Hisource Hi-K0801WS
Following is documentation for unmanaged switch marked as `Hi-K0801WS`.
Using SPI clamp in-board is the only method for initial installation.
### Label specifications
- **Name**: 2.5G Ethernet Switch
- **Model**: Hi-K0801WS
- **Ports**:
- 8 × RJ45: 10/100/1000/2500 Mbps
- 1 × SFP: 1000 / 2500 / 10000 Mbps
### What works (expected from label + similar devices)
- All eight 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
- SFP port supporting 1G, 2.5G and 10G modules
- LEDs
### PCB overview
**Board markings**
- Top silkscreen: PCB-KO801W-V2.0 / DIP-KO801WS-V2.0
Top side
<img src="photos/K0801W-V2.0-unmanaged\PCB-top.jpg" width="300" />
Bottom
<img src="photos/K0801W-V2.0-unmanaged\PCB-bottom.jpg" width="300" />
## Power supply
Input power is delivered via barell plug, `12V 1A` adapter was provided.
-23
View File
@@ -1,23 +0,0 @@
# K0501W V2.0
This board appears for example in the Davuaz Da-K6501W switch.
The general design of the board is similar to Hi-K0402WS V3.0.
However, there are several differences:
- One SFP port is replaced by a RTL8221B 2.5G PHY
- Only one LED is populated for the SFP port
- No mode switch and only one flash chip
- Older design using RTL8372 instead of RTL8372N (which also means different GPIO and LED configuration)
- Like earlier versions of the K0402W(S) board, there is no UART
All ports and LEDs are supported.
Installation is possible using a flash programmer.
The BoyaMicro 25Q16BSSIG flash chip is supported by flashprog with chip name "B.25D16AS/BY25Q16BS/BY25Q16ES".
## PCB pictures
The board is marked `PCB-K0501W-V2.0 DIP-K0501WS-V2.0`.
<img src="photos/K0501W_V2_0/pcb-top.jpg" width="300" />
<img src="photos/K0501W_V2_0/pcb-bottom.jpg" width="300" />
-93
View File
@@ -1,93 +0,0 @@
# Keeplink KP-9000-6XH-X2 / KP-9000-6XHML-X2
Following is documentation for switches marked as `KP-9000-6XH-X2` or
`KP-9000-6XHML-X2`.
Using SPI clamp in-board is the only method for initial installation.
### Label specifications
- **Name**: 4X 2.5G RJ45 Port + 2 X 10G SFP+ Port
- **Model**: KP-9000-6XH-X2 / KP-9000-6XHML-X2
- **Ports**:
- 4 × RJ45: 10/100/1000/2500 Mbps
- 2 × SFP+: 1000 / 2500 / 10000 Mbps
### Machine target
These devices exist with different PCB revisions. Select the machine target by
the PCB silkscreen, not by the label on the case. The `6XH` / `6XHML`
distinction appears to be a stock firmware, SKU or label difference, not a
reliable indicator of PCB wiring. The PCB revision defines the hardware layout.
| PCB silkscreen | Known labels / devices | Recommended machine target | Equivalent target | Legacy target |
| --- | --- | --- | --- | --- |
| `2M-PCB43-V1.1` | Mokerlink 2G040210GSM web-managed 4+2 switch | `MACHINE_KP_9000_6XHML_X2_V1_1` | `MACHINE_KP_9000_6XH_X2_V1_1` | `MACHINE_KP_9000_6XHML_X2` |
| `2M-PCB43-V1.2` | `KP-9000-6XHML-X2` | `MACHINE_KP_9000_6XHML_X2_V1_2` | `MACHINE_KP_9000_6XH_X2_V1_2` | `MACHINE_KP_9000_6XHML_X2` |
| `2M-PCB43-V2.1` | `KP-9000-6XH-X2`, `KP-9000-6XHML-X2` | `MACHINE_KP_9000_6XH_X2_V2_1` or `MACHINE_KP_9000_6XHML_X2_V2_1` | same V2.1 layout | `MACHINE_KP_9000_6XH_X2` |
The V1.1 and V1.2 boards currently use the same V1.x GPIO, SFP, port and LED
layout. The V2.1 board uses a different V2.1 layout with custom LED muxing.
Legacy targets are preserved for compatibility with already-tested devices, but
new builds should prefer the explicit PCB-revision targets.
### What works
- All four 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
- SFP port with 10G modules
- LEDs
- untested due to missing Hardware: SFP+ ports equipped with 1G or 2.5G SFPs.
### Hardware overview: 2M-PCB43-V2.1
Front side:
<img src="photos/2M-PCB43-V2.1-unmanaged/KP-9000-6XH-X2-front.jpg" width="600" />
Label:
<img src="photos/2M-PCB43-V2.1-unmanaged/KP-9000-6XH-X2-label.jpg" width="600" />
### PCB overview
**Board markings**
- Top silkscreen: 2M-PCB43-V2.1
Top side
<img src="photos/2M-PCB43-V2.1-unmanaged/2M-PCB43-V2.1-top.jpg" width="600" />
Bottom
<img src="photos/2M-PCB43-V2.1-unmanaged/2M-PCB43-V2.1-bottom.jpg" width="600" />
### Hardware overview: 2M-PCB43-V1.1 / V1.2
The V1.1 board has been reported in the Mokerlink 2G040210GSM web-managed 4+2
switch. The V1.2 board has been seen in managed `KP-9000-6XHML-X2` devices.
Both use the same V1.x layout.
Label:
<img src="photos/KP-9000-6XHML-X2/label.jpg" width="600" />
Top side:
<img src="photos/KP-9000-6XHML-X2/pcb_top.jpg" width="600" />
Bottom:
<img src="photos/KP-9000-6XHML-X2/pcb_bottom.jpg" width="600" />
## Reset Button
There's an unpopulated Reset button on the front left side of the PCB.
It can easily be soldered, you'll need an 4.5mmx4.5mm 90° button switch with a 3-pin footprint.
I got mine here: https://de.aliexpress.com/item/1005007295346702.html
The front case has already the hole in the metal case, you just have to punch a hole through the foil.
## Power supply
Input power is delivered via barell plug, `12V 1A` adapter was provided.
-97
View File
@@ -1,97 +0,0 @@
Hisource Hi-K0402WS V2
RTL8372-based 4×2.5G + 2×SFP+ unmanaged switch.
Using SPI clamp in-board is the only method for initial installation.
### Label specifications
- **Manufacturer**: HISOURCE
- **Model**: Hi-K0402WS V2
- **Ports**:
- 4 × RJ45: 10/100/1000/2500 Mbps
- 2 × SFP+: 1G / 2.5G / 10G
### What works
- All four 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
- Both SFP+ ports supporting 1G, 2.5G and 10G modules
- LEDs: amber (2.5G) and green (1G/100M/10M) per copper port; combined link/act on SFP ports
### PCB overview
**Board markings**
- PCB-K0402WS-V2.0
- DIP-K0402WS-V2.0
**Key components**
- U1: SPI NOR flash, 2 MiB
- S1: unpopulated slide switch footprint (three through-holes used as serial console)
Front panel
<img src="photos/PCB-K0402WS-V2.0/chassis-front.jpg" width="400" />
Bottom label
<img src="photos/PCB-K0402WS-V2.0/chassis-bottom.jpg" width="400" />
Top side (PCB)
<img src="photos/PCB-K0402WS-V2.0/PCB-top.jpg" width="300" />
### Port layout
| Front panel position | Logical port | Physical port | Type |
|----------------------|--------------|---------------|---------|
| SFP left | 8 | 5 | SFP+ |
| RJ45 1 | 4 | 1 | Copper |
| RJ45 2 | 5 | 2 | Copper |
| RJ45 3 | 6 | 3 | Copper |
| RJ45 4 | 7 | 4 | Copper |
| SFP right | 3 | 6 | SFP+ |
### Serial console
The PCB has three unpopulated through-holes intended for a slide switch, directly connected to UART0.
Numbered from the left (SFP port side), the pinout is:
| Position (left→right) | Signal | GPIO |
|-----------------------|--------|--------------------------|
| 1 (leftmost) | RX | GPIO32\_UART0\_RX (32) |
| 2 (middle) | GND | GND |
| 3 (rightmost) | TX | GPIO31\_UART0\_TX (31) |
- **Settings**: 115200 baud / 8N1 / 3.3V TTL
- Connect a USB-TTL adapter: adapter TX → pin 1, GND → pin 2, adapter RX → pin 3
### LED configuration
Copper ports use LED SET0, SFP ports use LED SET1.
| SET | LED0 | LED2 |
|------|--------------------------------------------------|---------------------------------------------------|
| SET0 | Amber — lights on 2.5G link | Green — lights on 1G / 100M / 10M link |
| SET1 | All speeds — lights on any link with activity | — |
LED pad to physical port mapping:
| GPIO pads | Port |
|-----------|-------------------------|
| GPIO8–11 | Physical port 5 (left SFP) |
| GPIO12–14 | Physical port 1 (RJ45 1) |
| GPIO15–17 | Physical port 2 (RJ45 2) |
| GPIO18–20 | Physical port 3 (RJ45 3) |
| GPIO21–23 | Physical port 4 (RJ45 4) |
| GPIO24–27 | Physical port 6 (right SFP) |
### SFP GPIO assignments
| SFP | pin\_detect (ModAbs) | pin\_los | SerDes | I2C SDA | I2C SCL |
|------------------|-----------------------------|------------------------|--------|----------------------|--------------------------|
| Left (logical 8) | GPIO30\_ACL\_BIT3\_EN | GPIO37 | SDS1 | GPIO39\_I2C\_SDA4 | GPIO40\_I2C\_SCL3\_MDC1 |
| Right (logical 3)| GPIO50\_I2C\_SCL2\_UART1\_TX | GPIO51\_I2C\_SDA2\_UART1\_RX | SDS0 | GPIO41\_I2C\_SDA3\_MDIO1 | GPIO40\_I2C\_SCL3\_MDC1 |
GPIO assignments were verified by observing GPIO state changes during SFP module insertion/removal
and cross-checked against an original firmware register dump.
`pin_tx_disable` is GPIO\_NA on both ports (original firmware keeps all GPIOs as inputs).
-79
View File
@@ -1,79 +0,0 @@
# PCB-K0402WS-V3.0
Following is documentation for a variety of unmanaged switch internally marked as `PCB-K0402WS-V3.0`. They are sold under many brands.
Original software is running UART on 9600 baud rate.
Note during opening the device: there might be a hidden 5th screw on the back
of the device just above the big label, might be covered by a QC sticker.
### Brands
* Hisource Hi-K0402WS
<img src="photos/PCB-K0402WS-V3.0/HiSource_HI-K0402WS.jpg" width="300" />
* Ztyuav Z-QWYT0402
<img src="photos/PCB-K0402WS-V3.0/Ztyuav_Z-QWYT0402.jpg" width="300" />
<img src="photos/PCB-K0402WS-V3.0/Ztyuav_Z-QWYT0402_label.jpg" width="300" />
* Siscolink SL-G0402F
<img src="photos/PCB-K0402WS-V3.0/Siscolink SL-G0402F.jpg" width="300"/>
### Programming
Using SPI clamp in-board is the only method for initial installation.
The board has two flash chips `BY25Q16BS` with 16M-bit size. The front switch, switches between the two flash chips.
These can be programed independently by using said switch - so it is e.g. possible to run the original and new firmware in parallel.
The switch actually controls the HOLD line of each flash chip, and toggling the switch results in a reboot.
If the programming clip keeps HOLD not connected, the flashing will commence on whatever the switch selected, regardless on which chip was clipped.
For the initial flash (at least with flashrom), the bin file produced by the build is much smaller than the flash chip, it is suggested to pad the file to keep flashrom happy: `truncate -s 2097152 rtlplayground-*-PCB_K0402WS_V3.bin`. Note: do not then proceed to use this resulting padded file for the web flashing (as it bricks the device), use the original unpadded .bin.
### What works (expected from label + similar devices)
- All four 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
- Both SFP ports supporting 1G, 2.5G and 10G modules
- LEDs
### PCB overview
**Board markings**
- Top silkscreen: PCB-KO4022W-V3.0 / DIP-KO4022WS-V3.0
Top side
<img src="photos/PCB-K0402WS-V3.0/PCB-top.jpg" width="300" />
Bottom
<img src="photos/PCB-K0402WS-V3.0/PCB-bottom.jpg" width="300" />
### T2, serial console
| `J2` pin | Signal |
| -------- | ----------- |
| 1 | 3V3 |
| 2 | RX (Input) |
| 3 | TX (Output) |
| 4 | GND |
## Power supply
Input power is delivered via barell plug, `12V 1A` adapter was provided.
Board has two supply rails. `0.95` and `3.3` volt.
### `0.95` Core Voltage
Voltage is made by a `Techcode TD1720` .
### `3.3` Voltage
Voltage is created by chip marked as `Techcode TD1720`.
**There seems to have been a miscalculation when choosing the inductor and the device is ~25% more efficient with an 5V power supply.**
-43
View File
@@ -1,43 +0,0 @@
# Steamemo IG204-V1
Following is documentation for unmanaged switch marked as `IG204-V1`.
Using SPI clamp in-board is the only method for initial installation.
### Label specifications
- **Name**: 2.5G Ethernet Switch
- **Model**: IG204 V1
- **Ports**:
- 4 × RJ45: 10/100/1000/2500 Mbps
- 2 × SFP: 1000 / 2500 / 10000 Mbps
### What works (expected from label + similar devices)
- Four 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
- Two SFP ports supporting 1G, 2.5G and 10G modules
- LEDs
### PCB overview
**Board markings**
- Top silkscreen: PB-2131
Top side
<img src="photos/STEAMEMO_IG204_V1/PCB-top.jpg" width="600" />
### Connectors
### T7, serial console
| `T7` pin | Signal |
| -------- | ----------- |
| 1 | TX (Output) |
| 2 | GND |
| 3 | RX (Input) |
| 4 | 3V3 |
### Power supply
Input power is delivered via barell plug, `12V 1A` adapter was provided.
-6
View File
@@ -1,10 +1,4 @@
# SWTG018AS-A V2.0
## Brands
| Brand | Type |Managed| PCB | Flash | Chip RTL |
|--------|------------------|-------|------------------|-----------------|---------------|
| Ampcom | SWTG018AS-A V2.0 | No | SWTG018AS-A V2.0 | 2MB | 8273N + 8224N |
| Horaco | HC-SWTGW218AS-A | Yes | SWTG018AS-A V2.0 | 2MB(25Q16JVSIQ) | 8273N + 8224N |
The following is a documentation for the unmanaged switch marked as `SWTG018AS-A V2.0`.
It is e.g. sold under the Ampcom brand, but no branh-markings are found on the device.
-43
View File
@@ -1,43 +0,0 @@
### SWTG024AS-A-V2.0.1_4C_2SFP
It is highly similar to SWTG024AS-V2.0, with the only difference being the GPIO configuration for the SFP port.
## Brands
|Brand|Type|Managed|PCB|Flash|Chip RTL|
|---|---|---|---|---|---|
| Horaco | ZX-SG4T2 | | PCB-SWTG024AS-A-V2.0.1_19650 | P25D40SH | ??? |
### Label specifications
- **Name**:
- **Ports**:
- 4 × RJ45: 10/100/1000/2500 Mbps
- 2 × SFP+: 1000 / 2500 / 10000 Mbps
<img src="photos/SWTG024AS-A-V2_0_1_19650/horaco-zx-sg4t2-label.jpg" width="300" />
### What works
The device is fully supported:
- ALL 2.5GBASE-T RJ45 ports work at 10/100/1000/2500 Mbps
- The SFP+ port supports 1G, 2.5G and 10G modules
### PCB overview
**Board markings**
- Top silkscreen: PCB-SWTG024AS-A-V2.0.1_19650
Top side
<img src="photos/SWTG024AS-A-V2_0_1_19650/horaco-zx-sg4t2-pcb-top.jpg" width="300" />
Bottom
<img src="photos/SWTG024AS-A-V2_0_1_19650/horaco-zx-sg4t2-pcb-bottom.jpg" width="300" />
### J1, serial console
| `J1` pin | Signal |
| -------- | ----------- |
| 1 | 3V3 |
| 2 | GND |
| 3 | RX (Input) |
| 4 | TX (Output) |
-44
View File
@@ -1,44 +0,0 @@
### SWTG024AS-A-V2.0.1_5C_1SFP
It is highly similar to SWTG024AS-V2.0, with the only difference being the GPIO configuration for the SFP port.
## Brands
|Brand|Type|Managed|PCB|Flash|Chip RTL|
|---|---|---|---|---|---|
| Horaco | HC-SWTGW215AS | | PCB-SWTG024AS-A-V2.0.1_19650 | W25Q16JV | 8272N |
### Label specifications
- **Name**:
- **Ports**:
- 5 × RJ45: 10/100/1000/2500 Mbps
- 1 × SFP+: 1000 / 2500 / 10000 Mbps
<!-- <img src="" width="300" /> -->
### What works
The device is fully supported:
- ALL 2.5GBASE-T RJ45 ports work at 10/100/1000/2500 Mbps
- The SFP+ port supports 1G, 2.5G and 10G modules
- LEDs work with the same indiciations as the OEM firmware
### PCB overview
**Board markings**
- Top silkscreen: PCB-SWTG024AS-A-V2.0.1_19650
Top side
<!-- <img src="" width="300" /> -->
Bottom
<!-- <img src="" width="300" /> -->
### J1, serial console
| `J1` pin | Signal |
| -------- | ----------- |
| 1 | 3V3 |
| 2 | GND |
| 3 | RX (Input) |
| 4 | TX (Output) |
-49
View File
@@ -1,49 +0,0 @@
### SWTG024AS-V2.0
## Brands
|Brand|Type|Managed|PCB|Flash|Chip RTL|
|---|---|---|---|---|---|
| hongyavision | LG-SG5T1 | No | PCB-SWTG024AS-V2.0_16895 | 25Q40 | 8272 |
### Label specifications
- **Name**:
- **Ports**:
- 5 × RJ45: 10/100/1000/2500 Mbps
- 1 × SFP+: 1000 / 2500 / 10000 Mbps
- **Power**: 12V DC, 1A 5525 connector
<img src="photos/SWTG024AS-V2.0/label.jpg" width="300" />
### What works
The device is fully supported:
- ALL 2.5GBASE-T RJ45 ports work at 10/100/1000/2500 Mbps
- The SFP+ port supports 1G, 2.5G and 10G modules
- LEDs work with the same indiciations as the OEM firmware
- Online update does not work with 512KiB flash.
### PCB overview
**Board markings**
- Top silkscreen: PCB-SWTG024AS-V2.0
Top side
<img src="photos/SWTG024AS-V2.0/pcb_top.jpg" width="300" />
Bottom
<img src="photos/SWTG024AS-V2.0/pcb_bottom.jpg" width="300" />
### J1, serial console
| `J1` pin | Signal |
| -------- | ----------- |
| 1 | GND |
| 2 | RX (Input) |
| 3 | TX (Output) |
Note,`R52`、`R53`may not be installed.You need to bridge them using either solder or resistors.
## Power supply
Input power is delivered via barell plug, `12V 1A` adapter was provided.
+2 -2
View File
@@ -9,8 +9,8 @@ Also the RJ45 connectors can be all plastic/non-shielded or with metal shielding
|Brand|Type|Managed|PCB|PCB Label|Flash|Chip RTL|
|---|---|---|---|---|---|---|
| LIANGUO |SWTG024AS |No| SWTG024AS-v2.0-17452 | CM-23-11-2336 023-17453| 512 KiB | 8272 |
| Horaco |ZX-SWTG124AS | Yes | SWTG024AS-v2.0 | ??? | ??? | 8272 |
| Xikestore |SKS3200M-4GPY2XF | Yes | SWTG024AS-v1.0 | CM-23-08-2043 023-16721 | 2048 KiB | 8272 |
| Haraco |ZX-SWTG124AS | Yes | SWTG024AS-v2.0 | ??? | ??? | 8272 |
| Xikestore |SKS3200M-4GPY2XF | Yes | SWTG024AS-v1.0 | CM-23-08-2043 023-16721 | ??? | 8272 |
| Sodola | SL-SWTG124AS-D | Yes | SWTG024AS-v2.0-17452 | ??? | 2048 KiB | 8272 |
## PCB
-183
View File
@@ -1,183 +0,0 @@
# ZX-SWTGW215AS
## Brands
|Brand|Type|Managed|PCB|Flash|Chip RTL|
|---|---|---|---|---|---|
| Lianguo | ZX-SWTGW215AS | Yes | PCB-SWTG115AS-V2.0 | FM25Q16A | 8372 |
| sold as Lianguo, actual device unbranded | ZX-SWTGW215AS | Yes | PCB-SWTG115AS-V2.1 | W25Q16JVSIQ (2MiB) | 8372 |
## RTLPlayground target
Use machine target `MACHINE_LIANGUO_ZX_SWTGW215AS` for this device.
Physical hardware verification: 5x RJ45 ports + 1x SFP port.
Port 5 RJ45 is interfaced through a RTL8221B IC.
## Label (V2.0)
<img src="photos/ZX-SWTGW215AS-V2.0/label.jpg" width="300" />
## PCB (V2.0)
<img src="photos/ZX-SWTGW215AS-V2.0/pcb_top.jpg" width="300" />
<img src="photos/ZX-SWTGW215AS-V2.0/pcb_bottom.jpg" width="300" />
## PCB (V2.1)
<img src="photos/ZX-SWTGW215AS-V2.1/pcb-top.jpg" width="300" />
<img src="photos/ZX-SWTGW215AS-V2.1/pcb-bottom.jpg" width="300" />
## Connectors
### Port overview
```
┌──────────────────────────────────────────────────────────────────────────────────┐
│ ┌──────────┐ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ SFP (J4) │ │
│ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ PORT 6 │ │
│ │ PORT 1 │ │ PORT 2 │ │ PORT 3 │ │ PORT 4 │ │ PORT 5 │ │ LOG 8 │ │
│ O │ LOG 4 │ │ LOG 5 │ │ LOG 6 │ │ LOG 7 │ │ LOG 3 │ │ SerDes 1 │ │
│ RST └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └──────────┘ │
└──────────────────────────────────────────────────────────────────────────────────┘
```
| Type | RTLPlayground logical ports | Physical index |
|---|---|---|
| RJ45 | 3, 4, 5, 6, 7 | 1-5 |
| SFP | 8 | 6 |
### J4
* Location: SFP connector `J4`.
* Connected to: 10GMAC number 8, SerDes 1.
|`J4` SFP PINs | Signal | GPIO | Notes |
|---|---|---|---|
|3| TX_DISABLE | GPIO_NA | Not connected |
|4| MODDEF2 – SDA | GPIO39 | I2C SDA |
|5| MODDEF1 – SCL | GPIO40 | I2C SCL |
|6| MODDEF0 – PRESENT | GPIO30 | Detect |
|8| LOS | GPIO37 | RX Loss of Signal |
#### Notes
* Not all signals were mapped mechanically, hence they've been left out of documentation.
### T3, Slave Interface
This connector goes to U4 `I2C EEPROM` and U10 `SPI FLASH` (mappings identical to SWTG024AS).
For detailed Slave Interface functionality and protocol information, see [T3 documentation in SWTG024AS.md](SWTG024AS.md#t3-slave-interface).
|`T3` pin|what|Signal|
|---|---|---|
|1| U4-P6, 33R U10-P6 | I2C-SCL, SPI-CLK, Slave SCK/SCL/MDC/EE_SCL |
|2| GND | --- |
|3| U4-P5, U10-P5 | I2C-SDA, SPI-DI/DO, Slave SDI/SDA/MDIO/EE_SDA |
|4| VCC |
|5| 33R -> U10-P2 | SPI-DO/D1 |
|6| U10-P1 | SPI-CS |
#### Notes
* 1 pin is square shaped.
### T5, Serial Console
|`T5` pin|GPIO|Signal|
|---|---|---|
| 1 | GPIO31 | U0TXD (Output) |
| 2 | GND | |
| 3 | GPIO32 | U0RXD (Input) |
| 4 | 3V3 | |
#### Notes
* 1 pin is square shaped.
### T8
|`T8` pin|GPIO|Signal|
|---|---|---|
| 1 | GPIO46 | |
| 2 | GND | |
| 3 | GPIO48 | |
| 4 | 3V3 | |
| 5 | GPIO47 | |
| 6 | GPIO49 | |
#### Notes
* 1 pin is square shaped.
* Mapping unverified but assumed the same as [LIANGUO SWTG024AS](SWTG024AS.md#t8).
## Reset Circuit
| Function | GPIO |
|---|---|
| Reset button | GPIO54 |
### Notes
* Circuit is active-low
## GPIO
Note: T3/U4/U10-related signal annotations below are copied from [LIANGUO SWTG024AS T3 section](SWTG024AS.md#t3-slave-interface) as well as T8 port from [LIANGUO SWTG024AS T8 section](SWTG024AS.md#t8). They should be treated as assumed identical for ZX-SWTGW215AS as it has not been 100% confirmed true at the moment.
| HEX VAL. | GPIO | Component / Purpose | Notes | | GPIO | Component / Purpose | Notes |
| -------- | ------ | ---- | ---- | ---- | ---- | ---- | ---- |
| 00000001 | GPIO00 | | | | GPIO32 | T5-3 | U0RXD |
| 00000002 | GPIO01 | | | | GPIO33 | | |
| 00000004 | GPIO02 | | | | GPIO34 | | |
| 00000008 | GPIO03 | | | | GPIO35 | | |
| 00000010 | GPIO04 | | | | GPIO36 | | |
| 00000020 | GPIO05 | | | | GPIO37 | J4-8 | SFP LOS |
| 00000040 | GPIO06 | | | | GPIO38 | | |
| 00000080 | GPIO07 | | | | GPIO39 | J4-4 | SFP I2C SDA |
| 00000100 | GPIO08 | | | | GPIO40 | J4-5 | SFP I2C SCL |
| 00000200 | GPIO09 | | | | GPIO41 | | |
| 00000400 | GPIO10 | | | | GPIO42 | U10-P6, U4-P6, T3-1 | SPI FLASH CLK / I2C-SCL (from [LIANGUO SWTG024AS](SWTG024AS.md#gpio)) |
| 00000800 | GPIO11 | | | | GPIO43 | U10-P5, U4-P5, T3-3 | SPI FLASH DI/IO0 / I2C-SDA (from [LIANGUO SWTG024AS](SWTG024AS.md#gpio)) |
| 00001000 | GPIO12 | | | | GPIO44 | U10-P2, T3-5 | SPI FLASH DO/IO1 (from [LIANGUO SWTG024AS](SWTG024AS.md#gpio)) |
| 00002000 | GPIO13 | PORT1 LED GREEN | | | GPIO45 | U10-P1, T3-6 | SPI FLASH CS (from [LIANGUO SWTG024AS](SWTG024AS.md#gpio)) |
| 00004000 | GPIO14 | PORT1 LED ORANGE | | | GPIO46 | T8-1 | (from [LIANGUO SWTG024AS](SWTG024AS.md#gpio)) |
| 00008000 | GPIO15 | | | | GPIO47 | T8-5 | (from [LIANGUO SWTG024AS](SWTG024AS.md#gpio)) |
| 00010000 | GPIO16 | PORT2 LED GREEN | | | GPIO48 | T8-3 | (from [LIANGUO SWTG024AS](SWTG024AS.md#gpio)) |
| 00020000 | GPIO17 | PORT2 LED ORANGE | | | GPIO49 | T8-6 | (from [LIANGUO SWTG024AS](SWTG024AS.md#gpio)) |
| 00040000 | GPIO18 | PORT3 LED GREEN | | | GPIO50 | | |
| 00080000 | GPIO19 | PORT3 LED ORANGE | | | GPIO51 | | |
| 00100000 | GPIO20 | PORT4 LED GREEN | | | GPIO52 | | |
| 00200000 | GPIO21 | PORT4 LED ORANGE | | | GPIO53 | | |
| 00400000 | GPIO22 | PORT5 LED GREEN | | | GPIO54 | Reset Button | GPIO54_ACL_BIT2_EN |
| 00800000 | GPIO23 | PORT5 LED ORANGE | | | GPIO55 | | |
| 01000000 | GPIO24 | SFP LED GREEN | J4 | | GPIO56 | | |
| 02000000 | GPIO25 | | | | GPIO57 | | |
| 04000000 | GPIO26 | | | | GPIO58 | | |
| 08000000 | GPIO27 | | | | GPIO59 | | |
| 10000000 | GPIO28 | LED-SYSTEM | | | GPIO60 | | |
| 20000000 | GPIO29 | | | | GPIO61 | | |
| 40000000 | GPIO30 | J4-6 | SFP DETECT | | GPIO62 | | |
| 80000000 | GPIO31 | T5-1 | U0TXD | | GPIO63 | | |
## LEDs
| NAME | GPIO | Port(s) | Function | Notes |
| ---- | ---- | ---- | ---- | ---- |
| PORT1 LED GREEN | GPIO13 |5| Activity | LEDS_2G5, LEDS_LINK, LEDS_ACT |
| PORT1 LED ORANGE | GPIO14 | 5 | Speed | LEDS_1G, LEDS_100M, LEDS_10M, LEDS_LINK, LEDS_ACT |
| PORT2 LED GREEN | GPIO16 | 4 | Activity | LEDS_2G5, LEDS_LINK, LEDS_ACT |
| PORT2 LED ORANGE | GPIO17 | 4 | Speed | LEDS_1G, LEDS_100M, LEDS_10M, LEDS_LINK, LEDS_ACT |
| PORT3 LED GREEN | GPIO18 | 3 | Activity | LEDS_2G5, LEDS_LINK, LEDS_ACT |
| PORT3 LED ORANGE | GPIO19 | 3 | Speed | LEDS_1G, LEDS_100M, LEDS_10M, LEDS_LINK, LEDS_ACT |
| PORT4 LED GREEN | GPIO20 | 2 | Activity | LEDS_2G5, LEDS_LINK, LEDS_ACT |
| PORT4 LED ORANGE | GPIO21 | 2 | Speed | LEDS_1G, LEDS_100M, LEDS_10M, LEDS_LINK, LEDS_ACT |
| PORT5 LED GREEN | GPIO22 | 1 | Activity | LEDS_2G5, LEDS_LINK, LEDS_ACT |
| PORT5 LED ORANGE | GPIO23 | 1 | Speed | LEDS_1G, LEDS_100M, LEDS_10M, LEDS_LINK, LEDS_ACT |
| SFP LED GREEN | GPIO24 | 6 (SFP J4) | Multi-speed | LEDS_10G, LEDS_5G, LEDS_2G5, LEDS_1G, LEDS_100M, LEDS_LINK, LEDS_ACT |
| LED-SYSTEM | GPIO28 | --- | System status | --- |
## Notes
While [SWTG024AS.md](SWTG024AS.md) can be used as a general reference for hardware concepts and interface specifications, this device should not be assumed to be identical beside the difference implicitely highlighted below. Not all information has been validated for compatibility with the SWTG215AS. Consult the SWTG024AS documentation with caution and verify any critical details against this device's.
## Flashing
For devices with Winbond 25Q16JVSIQ, flashing is possible for example using flashprog with device "W25Q16.V". Note that you should not overwrite the whole flash to keep device-specific data (like the MAC address at 0x1fc000). Also, creating a backup of the entire falsh before is of course a very good idea.
-1
View File
@@ -6,7 +6,6 @@
| Mokerlink | ZX-SWTGW218AS | Yes| SWTG118AS-V2.0-16029 | 2MB (FM25Q16A)| 8273N + 8224N |
| Sodola | | | | | |
| Horaco | | | | | |
| XikeStor | SKS3200-8E1X | Yes | SWTG118AS-V2.1-17462 | 2MB (25Q16JVSIQ) | |
## Photos
+13 -12
View File
@@ -14,11 +14,10 @@ The memory chip is `Winbond W25Q16JV` with 16M-bit size.
1. 2.5G ports on all advertised speeds.
2. SFP+ communication.
3. Serial, Web UI.
4. All LEDs
## Known issues
None.
1. LEDs are not initialized properly.
## PCB
@@ -39,10 +38,10 @@ Bottom
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ ┌──────────┐ ┌──────────┐ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ SFP 2 │ │ SFP 1 │ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ SFP │ │ SFP │ │
│ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ RJ45 │ │ PORT 5 │ │ PORT 6 │ │
│ │ PORT 1 │ │ PORT 2 │ │ PORT 3 │ │ PORT 4 │ │ MAC 8 │ │ MAC 3 │ │
│ │ MAC 4 │ │ MAC 5 │ │ MAC 6 │ │ MAC 7 │ │ SerDes 0 │ │ SerDes 1 │ │
│ │ PORT 1 │ │ PORT 2 │ │ PORT 3 │ │ PORT 4 │ │ MAC ? │ │ MAC ? │ │
│ │ MAC 4 │ │ MAC 5 │ │ MAC 6 │ │ MAC 7 │ │ SerDes ? │ │ SerDes ? │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
```
@@ -106,9 +105,9 @@ GPIO mapping unknown.
| 00000002 | GPIO01 | | GPIO33 | |
| 00000004 | GPIO02 | | GPIO34 | Random changes |
| 00000008 | GPIO03 | | GPIO35 | |
| 00000010 | GPIO04 | | GPIO36 | SFP2 Present |
| 00000020 | GPIO05 | | GPIO37 | SFP2 RX Los |
| 00000040 | GPIO06 | | GPIO38 | SFP1 Present |
| 00000010 | GPIO04 | | GPIO36 | SFP1 Present |
| 00000020 | GPIO05 | | GPIO37 | SFP1 RX Los |
| 00000040 | GPIO06 | | GPIO38 | SFP2 Present |
| 00000080 | GPIO07 | | GPIO39 | |
| 00000100 | GPIO08 | | GPIO40 | |
| 00000200 | GPIO09 | | GPIO41 | |
@@ -120,11 +119,11 @@ GPIO mapping unknown.
| 00008000 | GPIO15 | PORT2 Link | GPIO47 | SFP1 I2C SDA |
| 00010000 | GPIO16 | PORT2-LED-GREEN | GPIO48 | SFP2 I2C CLK |
| 00020000 | GPIO17 | PORT2-LED-AMBER | GPIO49 | SFP2 I2C SDA |
| 00040000 | GPIO18 | PORT3 Link | GPIO50 | SFP1 Rx LOS |
| 00080000 | GPIO19 | PORT3-LED-GREEN | GPIO51 | SFP2 TX Disable |
| 00040000 | GPIO18 | PORT3 Link | GPIO50 | SFP2 Rx LOS |
| 00080000 | GPIO19 | PORT3-LED-GREEN | GPIO51 | SFP1 TX Disable |
| 00100000 | GPIO20 | PORT4-LED-AMBER | GPIO52 | |
| 00200000 | GPIO21 | PORT4 Link | GPIO53 | |
| 00400000 | GPIO22 | PORT4-LED-GREEN | GPIO54 | SFP1 TX Disable |
| 00400000 | GPIO22 | PORT4-LED-GREEN | GPIO54 | SFP2 TX Disable |
| 00800000 | GPIO23 | PORT4-LED-AMBER | GPIO55 | |
| 01000000 | GPIO24 | | GPIO56 | |
| 02000000 | GPIO25 | | GPIO57 | |
@@ -137,6 +136,8 @@ GPIO mapping unknown.
## LEDs
Leds are not yet working as in stock firmware. This will be handled later.
Ports 1-4 are amber for 100M/1G links, Green for 2.5G.
Port 5-6 are green for 10G/1G link. Both should flash on activity.
@@ -165,7 +166,7 @@ Voltage is made by a `APW8713` (U3).
### `3.3` Voltage
Voltage is crated regulated by chip marked as `GoIAT` (U2).
Voltage is crated regulated by chip marke as `GoIAT` (U2).
## SFP SPI
-59
View File
@@ -1,59 +0,0 @@
# ZX310S-4T2XH/
The following is a documentation for the managed switch marked as `ZX310S-4T2XH`
and sold by Horaco.
The original software is running UART on 57600 baud rate. The solder holes
of the UART header are filled in. In order to install a UART header, they
need to be cleared first. A 1.2mm drill can be used, alternatively a
de-soldering wick.
The original firmware uses 57600 baud 8N1
CPU: RTL8372
Flash: 2MByte Winbond W25Q16DV (U3)
PHY RTL8261BE
### Label specifications
- **Name**:
- **Ports**:
- 4 × RJ45: 10/100/1000/2500 Mbps
- 1 x RJ45: 10/100/1000/2500/5000/10000 Mbps
- 1 × SFP+: 1000 / 2500 / 10000 Mbps
- **Power**: 12V DC, 2A barrel connector
<img src="photos/ZX310S-4T2XH/label.jpg" width="300" />
### What works
The device is fully supported:
- All 4 2.5GBASE-T RJ45 ports work at 10/100/1000/2500 Mbps
- The 10GBit port works. TODO: Fix EEE, speed selection
- The SFP+ port supports 1G, 2.5G and 10G modules
- LEDs work with the same indiciations as the OEM firmware
### PCB overview
**Board markings**
- Top silkscreen: PCB-SL310S-4T1T1X-V1.0.1-24107
Top side
<img src="photos/ZX310S-4T2XH/pcb_top.jpg" width="300" />
Bottom
<img src="photos/ZX310S-4T2XH/pcb_bottom.jpg" width="300" />
### J1, serial console
| `J1` pin | Signal |
| -------- | ----------- |
| 1 | TX (Output) |
| 2 | RX (Input) |
| 3 | GND |
| 4 | 3V3 |
## Power supply
Input power is delivered via barell plug, `12V 2A` adapter was provided.
-53
View File
@@ -1,53 +0,0 @@
# ZX310S-4T2XT
The following is a documentation for the managed switch marked as
`ZX310S-4T2XT` and sold by Horaco.
The original software is running UART on 57600 baud rate 8N1.
CPU: RTL8372
Flash: 2MByte Winbond W25Q16DV (U3)
PHY 2x RTL8261BE
### Label specifications
- **Name**:
- **Ports**:
- 4 × RJ45: 10/100/1000/2500 Mbps
- 2 x RJ45: 10/100/1000/2500/5000/10000 Mbps
- **Power**: 12V DC, 2A barrel connector
<img src="photos/ZX310S-4T2XT/label.jpg" width="300" />
### What works
The device is fully supported:
- All 4 2.5GBASE-T RJ45 ports work at 10/100/1000/2500 Mbps, including EEE
- The 10GBit ports works, including EEE.
- LEDs work with the same indiciations as the OEM firmware
### PCB overview
**Board markings**
- Top silkscreen: PCB-SL310S-4T2XT-V1.0.0-22273
Top side
<img src="photos/ZX310S-4T2XT/pcb_top.jpg" width="300" />
Bottom
<img src="photos/ZX310S-4T2XT/pcb_bottom.jpg" width="300" />
### J1, serial console
| `J1` pin | Signal |
| -------- | ----------- |
| 1 | TX (Output) |
| 2 | RX (Input) |
| 3 | GND |
| 4 | 3V3 |
## Power supply
Input power is delivered via barell plug, `12V 2A` adapter was provided.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 560 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 536 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 715 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 615 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 207 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 203 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 531 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 548 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 505 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 242 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 934 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 455 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 710 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 476 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 657 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 MiB

-98
View File
@@ -1,98 +0,0 @@
# GPIO Pin, Function and MUX registers.
These functions should bevalid for `RTL8372`, `RTL8372N`, `RTL8373`, and `RTL8373N`.
`N`-version doesn't seems to have all the GPIO pins available on the outside of the package.
| GPIO | Function | TYPE | MUX REG, BIT | (RTL8372) PIN# | (RTL8372N) PIN# |
| ----- | ---- | ---- | ---- | ---- | ---- |
| GPIO0 | LED0 | I/OPU | IO_MUX_SEL_0, BIT 0 | G1 | 12 |
| GPIO1 | LED1 | I/OPU | IO_MUX_SEL_0, BIT 1 | G2 | 15 |
| GPIO2 | LED2 | I/OPU | IO_MUX_SEL_0, BIT 2 | G3 | 14 |
| GPIO3 | LED3 | I/OPU | IO_MUX_SEL_0, BIT 3 | H1 | 16 |
| GPIO4 | LED4 | I/OPU | IO_MUX_SEL_0, BIT 4 | H2 | 18 |
| GPIO5 | LED5 | I/OPU | IO_MUX_SEL_0, BIT 5 | H3 | 20 |
| GPIO6 | LED6 | I/OPU | IO_MUX_SEL_0, BIT 6 | J1 | 22 |
| GPIO7 | LED7 | I/OPU | IO_MUX_SEL_0, BIT 7 | J2 | NoPin? |
| GPIO8 | LED8 | I/OPU | IO_MUX_SEL_0, BIT 8 | J3 | 24 |
| GPIO9 | LED9 | I/OPD | IO_MUX_SEL_0, BIT 9 | L1 | 23 |
| GPIO10 | LED10 | I/OPU | IO_MUX_SEL_0, BIT 10 | L2 | 26 |
| GPIO11 | LED11 | I/OPU | IO_MUX_SEL_0, BIT 11 | L3 | NoPin? |
| GPIO12 | LED12 | I/OPD | IO_MUX_SEL_0, BIT 12 | M1 | 28 |
| GPIO13 | LED13 | I/OPU | IO_MUX_SEL_0, BIT 13 | M2 | NoPin? |
| GPIO14 | LED14 | I/OPU | IO_MUX_SEL_0, BIT 14 | M3 | NoPin? |
| GPIO15 | LED15 | I/OPU | IO_MUX_SEL_0, BIT 15 | N1 | 25 |
| GPIO16 | LED16 | I/OPU | IO_MUX_SEL_0, BIT 16 | N2 | NoPin? |
| GPIO17 | LED17 | I/OPU | IO_MUX_SEL_0, BIT 17 | N3 | NoPin? |
| GPIO18 | LED18 | I/OPD | IO_MUX_SEL_0, BIT 18 | P1 | 30 |
| GPIO19 | LED19 | I/OPU | IO_MUX_SEL_0, BIT 19 | P2 | NoPin? |
| GPIO20 | LED20 | I/OPU | IO_MUX_SEL_0, BIT 20 | P3 | NoPin? |
| GPIO21 | LED21 | I/OPU | IO_MUX_SEL_0, BIT 21 | R1 | 27 |
| GPIO22 | LED22 | I/OPU | IO_MUX_SEL_0, BIT 22 | R2 | NoPin? |
| GPIO23 | LED23 | I/OPU | IO_MUX_SEL_0, BIT 23 | R3 | NoPin? |
| GPIO24 | LED24 | I/OPU | IO_MUX_SEL_0, BIT 24 | N19 | 88 |
| GPIO25 | LED25 | I/OPU | IO_MUX_SEL_0, BIT 25 | P19 | 86 |
| GPIO26 | LED26 | I/OPU | IO_MUX_SEL_0, BIT 26 | P18 | 84 |
| GPIO27 | LED27 | I/OPU | IO_MUX_SEL_0, BIT 27 | R19 | 82 |
| GPIO28 | SYS_LED | I/OPU | IO_MUX_SEL_0, BIT 28 | F1 | 13 |
| GPIO29 | GLB_RLDP_LED_EN | | IO_MUX_SEL_0, BIT 29 | | NoPin? |
| GPIO30 | ACL_BIT3_EN | | IO_MUX_SEL_2, BIT 3 | F3 | 11 |
| GPIO31 | UART TX (OUTPUT) | | IO_MUX_SEL_1, BIT 0 | L20 | 90 |
| GPIO32 | UART TX (INPUT) | | IO_MUX_SEL_1, BIT 1 | L21 | |
| GPIO33 | GPIO_INT | | IO_MUX_SEL_1, BIT 2 | | |
| GPIO34 | MDC0 | | IO_MUX_SEL_1, BIT 3 | | |
| GPIO35 | MDIO0 | | IO_MUX_SEL_1, BIT 4 | | |
| GPIO36 | PWM_OUT | | IO_MUX_SEL_1, BIT 30 | B13 | |
| GPIO37 | --- | | | L18 | |
| GPIO38 | --- | | | K19 | |
| GPIO39 | MSDA4 | | IO_MUX_SEL_1, BIT 29 | K20 | 95 |
| GPIO40 | MDC1/SCL3 | | IO_MUX_SEL_1, BIT 5 & 6 | J29 | |
| GPIO41 | MDIO1/MSDA3 | | IO_MUX_SEL_1, BIT 5 & 6 | J19 | |
| GPIO42 | SPI-MEMORY | | RTL8373_INI_MODE_ADDR, BIT 0 & 1 | D1 | |
| GPIO43 | SPI-MEMORY | | RTL8373_INI_MODE_ADDR, BIT 0 & 1 | E1 | |
| GPIO44 | SPI-MEMORY | | RTL8373_INI_MODE_ADDR, BIT 0 & 1 | D2 | |
| GPIO45 | SPI-MEMORY | | RTL8373_INI_MODE_ADDR, BIT 0 & 1 | E2 | |
| GPIO46 | MSCK0 | | IO_MUX_SEL_1, BIT 7 & 8 | A2 | |
| GPIO47 | MSDA0 | | IO_MUX_SEL_1, BIT 9 & 10 | B2 | |
| GPIO48 | MSCK1 | | IO_MUX_SEL_1, BIT 11 & 12 | A1 | |
| GPIO49 | MSDA1 | | IO_MUX_SEL_1, BIT 13 & 14 | B1 | |
| GPIO50 | MSCL2/U1TXD | | IO_MUX_SEL_1, BIT 15 & 16 | C1 | |
| GPIO51 | MSDA2/U1RXD | | IO_MUX_SEL_1, BIT 17 & 18 | C2 | |
| GPIO52 | ACL_BIT0_EN | | IO_MUX_SEL_2, BIT 0 | | |
| GPIO53 | ACL_BIT1_EN | | IO_MUX_SEL_2, BIT 1 | | |
| GPIO54 | ACL_BIT2_EN | | IO_MUX_SEL_2, BIT 2 | E5 | |
| GPIO55 | PTP_CLK125M_IN | | IO_MUX_SEL_1, BIT 19 | | |
| GPIO56 | PTP_CLK_OUT | | IO_MUX_SEL_1, BIT 20 | | |
| GPIO57 | PTP_TOD_OUT | | IO_MUX_SEL_1, BIT 21 | | |
| GPIO58 | PTP_PPS_OUT | | IO_MUX_SEL_1, BIT 22 | | |
| GPIO59 | PTP_TOD_IN | | IO_MUX_SEL_1, BIT 23 | | |
| GPIO60 | PTP_PPS_IN | | IO_MUX_SEL_1, BIT 24 | | |
| GPIO61 | SYNCELOCK0 | | IO_MUX_SEL_1, BIT 27 | | |
| GPIO62 | SYNCELOCK1 | | IO_MUX_SEL_1, BIT 28 | | |
| GPIO63 | GPIO_MDIO0 | | IO_MUX_SEL_1, BIT 4 | | |
## I2C
| I2C | Function |Type | (RTL8372) PIN# | (RTL8372N) PIN# |
| ---- | ---- | ---- | ---- | ---- |
| GPIO47 | SDA0 | I/OPU | | B1 | 142 |
| GPIO49 | SDA1 | I/OPU | | B2 | 144 |
| GPIO51 | SDA2 | I/OPU | | C2 | ??? |
| GPIO41 | SDA3 | I/OPU | | J20 | 98 |
| GPIO39 | SDA4 | I/OPU | | K20 | 95 |
| GPIO46 | SCL0 | I/OPU | | A2 | 138 |
| GPIO48 | SCL1 | I/OPU | | A1 | 140 |
| GPIO50 | SCL2 | I/OPU | | C1 | ??? |
| GPIO40? | SCL3 | OPU | | J20 | |
# Other funcitons
| Function | Type | (RTL8372) PIN# | (RTL8372N) PIN# |
| ---- | ---- | ---- | ---- |
| nRESET | | A6 | 131 |
| PTP_SYNC | | B10 | 130 |
| INT | OPU | B6 | 132 |
Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

-33
View File
@@ -65,36 +65,3 @@ ASIC and flushing the table in order to quickly forget the learned entries.
3c:18:a0:7e:11:00 0x0001 learned 5
1c:2a:a3:23:00:02 0x0001 learned 7
```
## Static multicast entries
Slow-protocol frames such as LACPDUs and STP BPDUs have to reach the CPU
without being flooded to the other ports. No bridge relays these frames:
their addresses are in the set that 802.1D-2004 clause 7.12.6 forbids a
bridge to forward, and what travels the network is the information, with
every bridge regenerating BPDUs of its own on its designated ports. The reserved-multicast *trap* action
cannot do that on this hardware, because its destination is an external CPU
attached to a physical port, which these boards do not populate. The protocol
modules therefore leave the reserved-multicast action at *forward* and constrain
the egress with a static L2 multicast entry instead: the lookup hits the entry's
own port mask rather than the VLAN flood mask. Verified on a SWTGW218AS both
ways, with the CPU bit cleared, where delivery stops, and with the CPU bit alone,
where nothing egresses.
`port_l2mc_set()` writes one such entry. The SMI layout is the L2 multicast
variant of the table entry:
```
DATA_IN_A = MAC bytes 5..2 -> c2 00 00 <mac_last>
DATA_IN_B = MAC[1..0] | vid<<16 | IVL<<29 | pmask[1:0]<<30
DATA_IN_C = pmask[9:2]
```
Lookups are IVL, so an entry made for VID 0 is never matched and a caller adds
one entry per PVID in use. The write goes through the table access register
with the table selector set to the L2 lookup table, `TBL_L2_UNICAST` in the
code, a name that despite appearances covers the multicast entries as well.
The hardware hashes MAC and VID to pick the bucket slot by itself.
Writing the same MAC and VID again replaces the entry rather than adding a
second one, so a caller can retarget the mask at will, for instance back to all
ports to restore flooding.
+4 -6
View File
@@ -48,11 +48,9 @@ void port_lag_hash_set(__xdata uint8_t lag, __xdata uint8_t hash_bits) __banked;
## LAG configuration on the Serial Console
For testing the following commands are provided on the serial console:
```
> lag <LAG-ID> <p1> [p2]...
Create or set a LAG. LAG-ID is 1 to 4. Ports are physical ports.
> lag <LAG-ID> d
Delete the LAG.
> lag <LAG-ID> [p1] [p2]...
Create or set a LAG. Trunk-ID is 1 or 2. Ports are physical ports
If only the LAG-ID is given but no members, the LAG is deleted
> lag show
Shows information on all 4 lags
@@ -94,7 +92,7 @@ The following shows the network configuration
On _both_ switches create a LAG with ports 1 and 2 inside and the default hash algorithm which takes
source and destination ports into account, e.g. just use the default:
```
> lag 1 1 2
> lag 0 1 2
```
+1 -4
View File
@@ -37,13 +37,10 @@ This list is incomplete.
| Brand | Partnumber |
| ---------- |----------- |
| GigaDevice | GD25Q32E |
| Fundan | FM25Q16A |
| Puya | P25D40SH |
| Winbond | W25Q16JV |
| Winbond | W25Q32FV |
| Winbond | W25Q32JV |
| Winbond | W25Q16JL |
| Winbond | W25Q16DV |
| Winbond | W25Q80DV |
| Fundan | FM25Q16A |
*NOTE*: Part numbers are incomplete. Part numbers may contain additional information such as package, temperature specifications, and even the number of devices on a reel. So always check the datasheet so that you have the right orderable partnumber.
-181
View File
@@ -1,181 +0,0 @@
# Spanning Tree (STP / RSTP)
The switch can take part in a spanning tree (IEEE 802.1D / 802.1w) so that
redundant links between bridges are blocked instead of forming a loop. The
implementation elects a root bridge from the BPDUs it receives, promotes ports
to forwarding once their listen period expires, ages the root out when it goes
silent, and blocks a port on which it sees its own BPDU.
STP can be enabled and controlled via the web interface or the command line,
as follows:
## Quick start
```
stp on # start participating
stp off # stop, all ports back to forwarding
```
Live status is on the Spanning Tree page of the web UI (or `/stp.json`),
and on the serial console via `stp status`.
With no other bridge around, the switch elects itself root and every port ends
up forwarding — you can leave it on safely. Put the settings in the startup
config to make them survive a reboot:
```
stp prio 15
stp port 1 edge on
stp on
```
## Hardware background
BPDUs are addressed to `01:80:C2:00:00:00`, a reserved link-local group. The
ASIC's Reserved-Multicast action for that address decides what happens to the
frame.
Forwarding to the CPU port works normally: the 8051 sits behind an ordinary
port of the internal switch and is an ordinary member of a forwarding mask.
The *trap* action does not deliver to it. Its destination is an external CPU
attached to a physical port (`cpuTag_externalCpuPort_set`, `EXT_CPU_CTRL` in
the vendor SDK), which these boards do not populate. The ACL trap and
redirect actions do not deliver to the 8051 either.
Delivery therefore uses the *forward* action, constrained to the CPU port
by a static L2 multicast entry (`port_l2mc_set()`), one per VLAN in use:
* while STP runs, the entry's member mask is the CPU port only — BPDUs reach
the CPU and are not flooded to other ports, as a participating bridge
requires;
* with STP off, the same entries are retargeted to all ports, restoring the
transparency an unmanaged switch is expected to have, so a surrounding
spanning tree can span *through* this device.
A BPDU delivered this way is an ordinary frame to the port's ingress logic
and passes through its acceptable-frame-type filter. BPDUs are untagged, so a
port set to admit tagged frames only (`ingress <port>t`) never delivers one
to the CPU. `stp_setup()` prints a warning for every STP-enabled port in that
state.
## Link aggregation
A LAG (Link Aggregation Group) is handled like an additional port by the STP
protocol, with its own timers and states. The switch devices support up to 4
LAGs, which are shown alongside the physical ports in the STP status. A group
carries its own path cost, priority, edge and guard settings, and gets its own
row on the Spanning Tree page.
```
stp lag 1 cost 10000 # the group decides, not its members
stp lag 1 edge off
```
LAGs are configured via the `lag` command. Once a port is a member of a LAG it
can no longer be configured individually for STP, so `stp port <n>` on a member
tells you which group to configure instead. Membership is re-read from the
aggregation registers once a second, so a group changing under LACP is picked
up without any coordination between the two.
The switch hardware does not handle STP state for a LAG as a whole. State
changes for the members have to be done by the firmware, updating every member
port, which is possible using a single register write. BPDUs go out through the
lowest member and carry the group's own port id. Losing one member of a live
LAG is not a topology change; the logical port only goes down with its last
link.
Port states live in `RTL837X_MSTP_STATES (0x5310)`, two bits per port:
`00` disabled, `01` blocking, `10` learning, `11` forwarding. A port in
blocking forwards nothing between ports, but it still sends what the CPU
hands it and still passes a received BPDU up to the CPU, which is what lets
loop detection go on working on a port it has already blocked.
## Timers
`stp_timers()` runs at 50 Hz (the main loop idles on the 200 Hz system tick and
STP is called every fourth pass), which is what `STP_HZ` in `rtl837x_stp.h`
encodes. All configured values are in seconds:
| setting | default | range |
|---|---|---|
| `stp hello <n>` | 2 | 1–10 |
| `stp maxage <n>` | 20 | 6–40 |
| `stp fwd <n>` | 15 | 4–30 |
| `stp txhold <n>` | 6 | 1–10 |
A port entering the tree spends `fwd` seconds in blocking before it forwards
(an edge port skips the wait). Root information is discarded after `maxage`
seconds without a BPDU, and the switch then reclaims the root role.
## Topology changes
A change on a local non-edge port (the link coming or going, a port promoted
to forwarding) flushes the addresses learned on it and sets the TC flag in
our BPDUs for `maxage + fwd` seconds. A TC flag received in a BPDU is passed
on: the switch flushes the other non-edge ports once and keeps the flag in
its own BPDUs until one hello after the last flagged frame, so the
notification crosses the switch instead of dying at it. A legacy TCN is
acknowledged with TCA and then treated like a local change.
## Bridge settings
```
stp prio <0-15> # bridge priority = n * 4096, default 8 (32768)
stp version rstp|stp # RST BPDUs (default) or legacy Config BPDUs
stp hello|maxage|fwd|txhold <seconds>
```
The bridge with the lowest priority wins the root election; ties are broken by
the MAC address. If you do not want this switch to become the root of an
existing network, give it a worse priority than the current root — `stp prio 15`
(61440) is the usual "never me" value.
## Per-port settings
```
stp port <1-9> on|off # take part in STP, or stay plain forwarding
stp port <1-9> edge on|off|auto # host-facing port handling (default: auto)
stp port <1-9> cost <0-200000000> # path cost, 0 = automatic (20000)
stp port <1-9> prio <0-240> # port priority, steps of 16
stp port <1-9> guard none|bpdu|root
stp port <1-9> filter on|off # neither send nor accept BPDUs
stp port <1-9> p2p auto|on|off
```
**edge** — an edge port forwards immediately and does not trigger a
topology change when its link comes and goes; `auto` promotes a port to edge
after three seconds without a BPDU, and demotes it as soon as one arrives. Use
`edge on` for ports where only hosts are attached.
**guard** — `bpdu` disables a port as soon as a BPDU arrives on it (a host port
should never see one); `root` keeps a port from ever becoming the path to the
root, which protects an existing topology from a newly attached bridge that
claims a better priority.
**filter** — the port neither sends nor accepts BPDUs. Useful when the device
on the far side reacts badly to them (some unmanaged switches with loop
prevention cut the link) but you still want STP on the rest of the ports.
## Status
The Spanning Tree page shows the elected root (priority and MAC), the path cost
to it, the root port, the topology-change counter and, per port, the live state
read from the ASIC together with the configured options. The same data is
available as JSON:
```
GET /stp.json
```
The `stp status` command prints the same view on the serial console.
## Limitations
* One spanning-tree instance; no MSTP, no per-VLAN trees.
* No proposal/agreement handshake — an RST-capable neighbour will still
converge, but through the timers rather than the fast transition.
* Port roles are approximated: the root port and designated ports are
distinguished, alternate/backup are not.
* Topology changes propagate away from the root only: nothing is announced
on the root port (no TCN and no BPDUs at all), so bridges upstream rely on
their own detection.
-135
View File
@@ -1,135 +0,0 @@
# Supporting Multiple Languages in the Web UI
The firmware uses a client-side i18n approach
all translations are stored in a single JavaScript dictionary embedded in the firmware.
No server-side changes are needed.
## Architecture
All translation logic lives in `html/i18n.js`. The file contains:
- A `LANG` object with one sub-object per language (`en`, `ja`, ...)
- Language auto-detection (browser language → `localStorage` override)
- `t(key)` — look up a translated string
- `setLang(lang)` — switch language and update the page
- `applyTranslation(el)` — apply translation to one DOM element
Translation keys are **flat strings** (no nesting). The English keys in `LANG.en` also serve as the fallback when a key is missing in another language.
## How to Add a New Language
### 1. Add a dictionary entry in `html/i18n.js`
Append a new sub-object to the `LANG` object. Every key from `LANG.en` must be present:
```js
var LANG = {
en: {
nav_overview: 'Overview',
nav_port_config: 'Port Configuration',
// ... all keys for English
},
ja: {
nav_overview: '概要',
nav_port_config: 'ポート設定',
// ... all keys for Japanese
},
LANGCODE: { // ← add your language here
nav_overview: '...',
nav_port_config: '...',
// ... translate every key
},
};
```
### 2. Add the language to the navigation sidebar
In `html/navigation.js`, add an `<option>` to the language selector:
```js
+ "<option value='en'>English</option><option value='ja'>日本語</option>"
```
Replace with:
```js
+ "<option value='en'>English</option><option value='ja'>日本語</option><option value='LANGCODE'>Native Name</option>"
```
### 3. Verify auto-detection
The language detection code in `i18n.js` reads `navigator.language` and normalises it to the first two characters:
```js
var browser = (navigator.language || navigator.userLanguage || 'en').substring(0, 2);
return LANG[browser] ? browser : 'en';
```
If the two-letter code matches a key in `LANG`, it will be auto-selected. No changes needed here.
## Two Translation Mechanisms
### (A) `data-i18n` attribute (declarative — for HTML)
Add `data-i18n="key_name"` to any HTML element. The English text goes in the element content as a fallback:
```html
<h1 data-i18n="port_heading">Port Configuration</h1>
<input type="button" data-i18n="port_apply" value="Apply">
<option data-i18n="port_auto">Auto</option>
<title data-i18n="port_title">Port Configuration</title>
```
On page load, `applyTranslation()` sets:
- `el.value` for `<input type="submit|button">`
- `el.textContent` for `<option>`, `<title>`
- `el.innerHTML` for everything else
### (B) `t('key')` call (imperative — for JavaScript strings)
When generating HTML or text in JavaScript, wrap translatable strings with `t()`:
```js
td.appendChild(document.createTextNode(t('common_port') + i));
td.innerHTML = t('port_auto');
iHTML += "<tr><td>" + t('port_vendor') + "</td></tr>";
```
### Special Case: Link Speed Display
The `linkS` array in `html/main.js` maps numeric link states to display strings. The first two entries (`speed_disabled`, `speed_down`) use `t()` for translation; the remaining entries are static literals (they are the same in all languages):
```js
const linkS = [
function(){return t('speed_disabled')},
function(){return t('speed_down')},
"10M", "100M", "1000M", "500M", "10G", "2.5G", "5G"
];
function linkText(idx) { var v = linkS[idx]; return typeof v === 'function' ? v() : v; }
```
Always use `linkText(idx)` (not `linkS[idx]`) to read these values.
## Size Considerations
- `html/i18n.js` is embedded in the firmware filesystem (~14 KB for two languages)
- Each new language adds roughly the same number of bytes as the English dictionary (~3–4 KB)
- The firmware binary is padded to 512 KiB, so a few extra KB do not change the flash footprint
- Values that are identical in all languages should be inlined as literals rather than added to the dictionary (e.g., `"10M"`, `"2.5G"`, `"MAC"`, `"VLAN"`, `"CPU"`)
## Build
No special flags are needed. The `html/` directory is embedded by `fileadder` during the build.
## Script Load Order
`i18n.js` must be loaded after `main.js` (which defines `t()`'s dependencies like `LANG`) but before any page-specific JS that calls `t()`:
```html
<script src="/main.js"></script>
<script src="/i18n.js"></script>
<script src="/eee.js"></script> <!-- uses t() -->
```
The `navigation.js` script is loaded last (bottom of `<body>`).
+11 -38
View File
@@ -1,44 +1,17 @@
# Supported Hardware
The following devices have been tested and are fully working:
- Horaco ZX_SG4T2
- keepLINK kp-9000-6hx-x2 (RTL8372: 4x 2.5GBit + 2x 10GBit SFP+)
- keepLINK KP-9000-6XHML-X2, same as above, but Managed
- keepLINK kp-9000-6hx-x (RTL8372 + RTL8221B 2.5GBit PHY: 5 x 2.5GBit + 1x 10GBit SFP+)
- keepLINK kp-9000-9xh-x-eu (1 x RTL8373 + RTL8224: 8x 2.5GBit + 1x 10GBit SFP+)
- Lianguo LG-SWTGW218AS (RTL8373 + RTL8224 PHY: 8x 2.5GBit + 1x 10GBit SFP+)
- No-Name ZX-SWTGW215AS, managed version of kp-9000-6hx-x, ordered on
AliExpress as keepLINK 5+1 port managed
- TrendNet TEG-S562 (RTL8372: 4x 2.5GBit + 2x 10GBit SFP+)
| Brand | Type | Managed | PCB | Flash | Ports |
|----------|-----------------|---------|---------------------------------------------------------------------------|-------|-------|
| Ampcom | WAM902-SWTG018AS| No | [SWTG018AS-A V2.0](devices/SWTG018AS_A_V2_0.md) | | 8 + 1 |
| Davuaz | Da-K6501W | No | [PCB-K0501W-V2.0](devices/K0501W_V2_0.md) | | 5 + 1 |
| FOXNEO | FNS-1200P | No | [PCB-K0402W-U13-V2.0](devices/FNS-1200P.md) | 2M | 4 + 2 |
| Hisource | Hi-K0402WS | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 |
| Hisource | Hi-K0402WS | No | [PCB-K0402WS-V2.0](devices/PCB-K0402WS-V2.0.md) | 2M | 4 + 2 |
| Hisource | Hi-K0801WS | No | [PCB-KO801W-V2.0](devices/HI-K0801WS.md) | | 8 + 1 |
| hongyavision | LG-SG5T1 | No | [PCB-SWTG024AS-V2.0_16895](devices/SWTG024AS-V2.0.md) | 0.5M | 5 + 1 |
| Horaco | HC-SWTGW215AS | Yes | [SWTG024AS-A-V2.0.1_19650 5C 1SFP](devices/SWTG024AS-A-V2.0.1_5C_1SFP.md) | ? | 5 + 1 |
| Horaco | HC-SWTGW218AS | Yes | [SWTG018AS-A V2.0](devices/SWTG018AS_A_V2_0.md) | | 8 + 1 |
| Horaco | ZX310S-4T2XH | Yes | [PCB-SL310S-4T1T1X-V1.0.1-24107](devices/ZX310S-4T2XH.md) | 2M | 5 + 1 |
| Horaco | ZX310S-4T2XT | Yes | [PCB-SL310S-4T2XT-V1.0.0-22273](devices/ZX310S-4T2XT.md) | 2M | 6 |
| Horaco | ZX-SG4T2 | No | [SWTG024AS-A-V2.0.1_19650_4C_2SFP](devices/SWTG024AS-A-V2.0.1_4C_2SFP.md) | 0.5M | 4 + 2 |
| Horaco | ZX-SWTG124AS | Yes | [SWTG024AS-v2.0](devices/SWTG024AS.md) | | 4 + 2 |
| Keeplink | KP-9000-6XH-X2 / KP-9000-6XHML-X2 | No/Yes | [2M-PCB43-V1.2 / V2.1](devices/KP-9000-6XH-X2.md) | | 4 + 2 |
| keepLINK | KP-9000-9XHML-X | Yes | [2M-PCB23-V2.2](devices/2M-PCB23-V2_2.md) | 2M | 8 + 1 |
| keepLINK | KP-9000-9XHML-X | Yes | [2M-PCB23-V3.1](devices/2M-PCB23-V3_1.md) | 2M | 8 + 1 |
| LIANGUO | SWTG024AS | No | [SWTG024AS-v2.0-17452](devices/SWTG024AS.md) | 0.5M | 4 + 2 |
| Lianguo | ZX-SWTGW215AS | Yes | [PCB-SWTG115AS-V2.0 / PCB-SWTG115AS-V2.1](devices/SWTGW215AS.md) | 2M | 5 + 1 |
| Mokerlink| 2G040210GSM | Yes | [2M-PCB43-V1.1](devices/2M-PCB43-V1.1.md) | | 4 + 2 |
| Mokerlink| ZX-SWTGW218AS | Yes | [SWTG118AS-V2.0-16029](devices/SWTGW218AS.md) | 2M | 8 + 1 |
| MokerLink| POE-2G080110GS | No | [2M-PCB51-ML-V1.1](devices/2M-PCB51-ML-V1_1.md) | 4M | 8 + 1 |
| Ruiying | RY-4GT-2SX | No | [FG-4GT-2SX_V2.0](devices/FG-4GT-2SX_V2.0.md) | 4M | 4 + 2 |
| Ruiying | RY-8GT-1SX | No | [FG-8GT-1SX](devices/FG-8GT-1SX.md) | 1M | 8 + 1 |
| SiscoLink | SL-G0402F | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 |
| Sodola | SL-SWTG124AS-D | Yes | [SWTG024AS-v2.0-17452](devices/SWTG024AS.md) | 2M | 4 + 2 |
| Steamemo | IG204-V1 | No | [PB-2131](devices/STEAMEMO_IG204_V1.md) | | 4 + 2 |
| TrendNet | TEG-S562 | No | [TEG-S563/EU H/W: V1.0R](devices/TEG-S562.md) | 2M | 4 + 2 |
| Xikestore| SKS3200M-4GPY2XF| Yes | [SWTG024AS-v1.0](devices/SWTG024AS.md) | | 4 + 2 |
| XikeStor | SKS3200-8E1X | Yes | [SWTG118AS-V2.1-17462](devices/SWTGW218AS.md) | 2M | 8 + 1 |
| Ztyuav | Z-QWYT0402 | No | [PCB-K0402WS-V3.0](devices/PCB-K0402WS-V3.0.md) | | 4 + 2 |
For KP-9000-6XH-X2 / KP-9000-6XHML-X2 / Mokerlink 2G040210GSM devices, select
the machine target by PCB revision. The ML/non-ML or managed/unmanaged label
alone does not identify the wiring.
Other device based on RTL8272/3 that may work are described here: [Up-N-Atoms 2.5 GBit RTL Switch hacking guide](https://github.com/up-n-atom/SWTG118AS)
Other device based on RTL8272/3 that may work are described here: [Up-N-Atoms 2.5 GBit RTL Switch hacking guide]
(https://github.com/up-n-atom/SWTG118AS)
Many of the RTL8272/3 devices come in versions with PoE support. The RTLPlayground usually also
works on these, however, no support for configuring PoE is provided, simply because these
Loaded 100 of 186 files, more files were not shown because too many files have changed in this diff. Show more