60 Commits
Author SHA1 Message Date
René van Dorst 1db30f22de Merge pull request #330 from vDorst/SRAM-easy-changes
Sram easy changes
2026-08-29 18:33:29 +00:00
logicog 4c70e654d1 Merge pull request #363 from vDorst/refactor_remove_keyword_register
Remove register keyword from all the function arguments.
2026-08-29 11:56:22 +02:00
feelfree69 3c24f2bdea Merge pull request #260 from donbernhardo/fix-kp-9000-6xhml-x2-led-mux
Add KP-9000 6XH and 6XHML PCB-revisions to Machine targets
2026-08-29 10:16:16 +02:00
donbernhardo 3e610392a9 Merge remote-tracking branch 'origin/main' into fix-kp-9000-6xhml-x2-led-mux
# Conflicts:
#	machine.c
2026-08-28 23:01:38 +02:00
René van Dorst 146771f5ca Merge pull request #362 from bloqaudio/fix/v210-bank0
leds: move the SWTG018AS-V2.1.0 custom LED init to BANK2
2026-08-27 16:32:09 +02:00
René van Dorst bf0bea1edd Remove register keyword from all the function arguments.
Adds no value.
2026-08-26 21:52:31 +02:00
René van Dorst 907ad08830 uip: uip_arp_update() put more arguments in xdata
Saves 7-bytes.
2026-08-26 20:51:32 +02:00
René van Dorst 7cf0115182 httpd: scan_header() put argument on xdata
Saves 2 bytes
2026-08-26 20:51:32 +02:00
René van Dorst adfbead438 syslog: syslog_callback() put local variables on xdata.
Save atleast 2 bytes.
2026-08-26 20:51:32 +02:00
René van Dorst 301774040b uip: place some pointer in xdata.
Saves 2 bytes.
2026-08-26 20:51:32 +02:00
René van Dorst 683037f410 httpd: rename gen_random_bytes to gen_random_hex_chars
This reflexs the function better.
Moving `byte` arguments to __xdata which saves 1 SRAM byte.
2026-08-26 20:51:27 +02:00
René van Dorst 57b820c4e8 httpd: mark pointer variable as __xdata.
Otherwise it is put on SRAM location.

Saves 6 SRAM bytes
2026-08-26 20:49:58 +02:00
bloqaudio 801150431b stp: host the spanning tree module in BANK2
All entry points are already __banked and none of the code runs in
interrupt context, so the module can leave the resident bank. This
relieves pressure on bank 0, which no longer fits a machine with a
custom init table.
2026-08-25 10:05:19 -05:00
logicog 45d0aac118 Merge pull request #326 from vDorst/SRAM-cmd-parse-port-helper
Add/refactor helpers to parse IP, numbers and port arguments
2026-08-25 12:49:00 +02:00
René van Dorst ee05cd4000 Fix: send_counters(), port-argument have to be physical port number.
Not the physical port index!
2026-08-25 07:55:17 +02:00
René van Dorst 74013bb14f CMD: Treat port zero as CPU-port 2026-08-25 07:55:17 +02:00
René van Dorst beb14deba5 httpd: send_counter(): Validate phys_port_idx and better error handling 2026-08-25 07:55:17 +02:00
René van Dorst 1212def799 CMD: fixes many comments 2026-08-25 07:55:17 +02:00
René van Dorst 95b3bde822 Rename print_port() to print_phys_port() 2026-08-25 07:55:17 +02:00
René van Dorst f511453f79 CMD: refactor code 2026-08-25 07:55:17 +02:00
René van Dorst 8653216047 CMD: Fix some comments 2026-08-25 07:55:17 +02:00
René van Dorst e62e0fc8bd CMD: Isolate allow the CPU-port as a member. 2026-08-25 07:55:17 +02:00
René van Dorst 2ff418f80f Replace '\0' to NUL to make it more clear that it is a NUL-terminated string. 2026-08-25 07:55:06 +02:00
René van Dorst 5d42e8843e Rename cmd_is_space_or_null to cmd_is_space_or_nul 2026-08-25 07:54:15 +02:00
René van Dorst 3c183f73f8 Added print_port() helper to print physical port number. 2026-08-25 07:54:15 +02:00
René van Dorst 3776f12f5c Fix and refactor parse_bw() 2026-08-25 07:54:15 +02:00
René van Dorst 5ddec9710a CMD: Fix parse_lag_hash() 2026-08-25 07:54:15 +02:00
René van Dorst f627559005 fix CMD: pvid: remove atoi_results_u8 from check 2026-08-25 07:54:15 +02:00
René van Dorst dca92d7f45 cmd_parse_port_separator() cmd_parse_port() remove CPU-port support
Removing the CPU-port support, As stated in #334, it is not needed to
manual add the CPU-port to any command. Because the CPU-port should be
added automatilly when CPU-port is needed.

Refactor cmd_parse_port() because port number is only 1 byte.
This simplifies the parsing code.

Refactor cmd_parse_port_separator() to ensure the return size is correct.
2026-08-25 07:54:15 +02:00
René van Dorst 149dc8537f Rename cmd_parse_port_space() to cmd_parse_port_separator()
cmd_parse_port_separator() parse the full port number and checks that the
number end with a NUL of space.
Now this function can also be used to parse the last argument number
because this ends with a NUL.

Also refactor code.
2026-08-25 07:54:15 +02:00
René van Dorst 42f7b4fba1 Fix parse_isolate(), ensure spaces between arguments 2026-08-25 07:54:15 +02:00
René van Dorst 17642699d4 Improve parse_ingress() 2026-08-25 07:54:15 +02:00
René van Dorst 724fd1e061 Added print_ip() to print IPv4 addresses. 2026-08-25 07:54:15 +02:00
René van Dorst 3eb2dfe0c9 Change parse_ip() 2026-08-25 07:54:15 +02:00
René van Dorst 73df006d39 Replace all manual port parsing with cmd_parse_port_space() or cmd_parse_port().
Saves no SRAM but around 1k code size
2026-08-25 07:54:15 +02:00
René van Dorst 175f3bb185 Add cmd_parse_port() and cmd_parse_port_space() helper.
A lot of places we manual parse and translate the port.
These helper functions will do that for us.
2026-08-25 07:54:15 +02:00
René van Dorst 57061161b6 Refactor code to make use of new atoi_byte() 2026-08-25 07:54:15 +02:00
René van Dorst 80f97a50e0 Refactor atoi_byte() same as atoi_short() 2026-08-25 07:54:15 +02:00
René van Dorst c265a20d83 Refactor the code for the new atoi_short()
Free-up 1 SRAM-byte
2026-08-25 07:54:15 +02:00
René van Dorst 4937618684 Change atoi_short() so it returns number of bytes consumed. 2026-08-25 07:54:15 +02:00
bloqaudio 1a743b3889 leds: reduce the SWTG018AS-V2.1.0 custom init to the effective registers
Measured against the generic leds_setup() output on the board: eight of
the 21 stock values are identical to what leds_setup() computes from
the machine's led_mux table, and eight more revert to the generic
values with no change in LED behaviour in any tested link state (copper
2.5G, SFP 2.5G, SFP 10G). Keep the five with a measurable effect: 6528
selects blue over green at 10G, 6540/6548 carry the SFP and copper LED
set behaviour, 65dc enables the LED outputs, and PIN_MUX_0 routes the
blue pin.

Verified from a clean boot on a SWTG018AS-V2.1.0 board: copper solid
green with activity blink at 2.5G on two ports, SFP green at 2.5G,
SFP blue at 10G, LEDs off on link down.
2026-08-24 23:44:36 -05:00
bloqaudio 425283b774 machine: host the per-machine custom init hooks in BANK2
machine_custom_init() runs once at boot, but its code and any tables it
uses were compiled into machine.c and so into the common bank. On the
SWTG018AS-V2.1.0 variant, whose init carries a 21-entry LED register
table, that overflows bank 0 by 0x66 bytes and main no longer links for
MACHINE_PCB_SWTG018AS_V2_1_0; any machine whose init grows can hit the
same wall. SDCC segment pragmas apply file-wide, so the hooks move to a
new machine_init.c compiled into BANK2, and the prototype becomes
banked. machine_check also compiles the new file per machine so the
hooks keep CI syntax coverage.
2026-08-24 23:36:17 -05:00
logicog f582576b10 Merge pull request #345 from DrDoof/fix/sfp-i2c-error
sfp: notice when an I2C read fails
2026-08-25 05:13:47 +02:00
feelfree69 16b0f207ed Merge pull request #317 from bloqaudio/pr/swtgw218as-sfp-led
machine: add PCB SWTG018AS-V2.1.0 variant of the SWTGW218AS
2026-08-25 02:22:21 +02:00
René van Dorst fe2bcc7f2d Merge pull request #356 from bloqaudio/fix/config-post-race
httpd: buffer a configuration upload before touching the flash
2026-08-24 23:35:19 +00:00
d00f a0628c7df5 sfp: read the EEPROM in blocks instead of a byte at a time
The I2C controller transfers up to sixteen bytes per transaction and
page_impl.c already used that for sfp_send_data(), while sfp_read_reg()
asked for one byte and every caller looped. Reading a module therefore
cost one address phase per byte: 87 transactions when a module is
inserted, 52 for the sfp command, 36 for the vendor block in status.json.

sfp_read_block() replaces sfp_read_reg() and the callers that already
wanted a run of registers ask for it once: the vendor fields as three
16 byte pages, the diagnostics as one transfer, rate and encoding
together. That drops the three paths above to 8, 6 and 3 transactions,
and sfp_send_data() loses its copy of the transfer.

The vendor loops now run over 16..63 rather than 20..59 so the page base
is a multiple of sixteen and the index into the buffer is a single AND.
The four extra bytes at each end are read and discarded. The diagnostics
read asks for 16 bytes rather than the 15 it uses, because 16 is a width
the shipped firmware already exercises and 15 is not.

The device address, the bus selection and the start bit go into the
control register in one write now that the memory address is written
first, so a transfer touches that register once instead of three times.
The register reads take their result from the SFRs directly rather than
through the sfr_data mirror. The result is a bool and the destination is
sfp_buf, so a caller that cares about a failed transfer looks at the
return value instead of a flag.

Every caller gives up on the first failed read rather than carrying a
flag to the end, which is why the module read moved out of handle_sfp
into a function of its own. A module whose read fails is left marked as
absent, so the next poll retries it instead of configuring the SerDes
from bytes that never arrived.

BANK1 -194 bytes, BANK2 +382, common segment +44, xdata +15 for the
buffer, and one byte more of internal RAM free than before the series.
Built for all 25 machine definitions on sdcc 4.5.0; the tightest common
segment is 98 bytes free on SWTG024AS_V2_0, against 54 before this
series.
2026-08-25 01:09:20 +02:00
bloqaudio cefe48fe51 httpd: size the config upload buffer for a full config sector
CONFIG_UPLOAD_BUF at 2560 capped a configuration upload at about 2.2K
while the config sector holds 4K. Size the buffer as CONFIG_LEN plus
room for the multipart framing so the whole sector is usable.

config_take() wrote the payload without checking it against the sector:
safe before only because the buffer could not hold an oversized one.
Reject a payload that does not fit CONFIG_LEN, terminator included,
instead of writing past the erased sector.
2026-08-24 15:45:25 -05:00
bloqaudio e8e7fcbe7f httpd: send the config tail from the config sector, not a bare offset
send_config() streams a configuration larger than the TCP output buffer
through the cont_addr/cont_len continuation, but set cont_addr to the
offset within the config instead of a flash address, so the tail was read
from code space. The file server sets cont_addr absolute; do the same by
adding CONFIG_START.

The bug was unreachable while CONFIG_UPLOAD_BUF capped uploads below
TCP_OUTBUF_SIZE, but a stored config near the full sector exposes it.
2026-08-24 15:45:25 -05:00
donbernhardo 8a28b4fc88 Merge upstream main and resolve conflicts 2026-08-24 10:51:27 +02:00
d00f 9a96c80af2 sfp: move the I2C transfer to the banked pins module
sfp_read_reg() sat in rtlplayground.c, so it occupied the common 16 KB
window that every bank shares, even though nothing outside the SFP paths
calls it. That window is the tightest resource in the image:
SWTG024AS_V2_0 and SWTG024AS_A_2_0_1_5C_1SFP had 54 bytes left in it.

rtl837x_pins.c is already in BANK2 and already holds the I2C bus helpers
this function calls, so the transfer belongs there. The function moves
verbatim and becomes __banked; the prototype in rtl837x_common.h says so,
which is what keeps the callers in BANK1 and BANK2 honest.

No behaviour change. The common segment gains 200 bytes on every machine:
159 to 359 free on SWTGW218AS, 54 to 254 on the two variants above.
BANK1 +6 bytes, BANK2 +336. Built on sdcc 4.5.0.
2026-08-24 02:34:39 +02:00
bloqaudio 772e9dc526 httpd: parse a configuration upload once the whole request has arrived
Saving the configuration works in Chrome and fails in Firefox, and the
difference is only how each browser splits the request. The handler
erased the config sector as soon as the request started and then parsed
the multipart body one TCP segment at a time, which requires every
boundary and every part header to fall inside a single segment. Firefox
splits inside a part header, so the parser lost its place and the
erased sector was left holding a truncated body or nothing at all. A
single-burst scripted post lost the whole body the same way.

The configuration is limited to two kilobytes, so the whole request body
now accumulates in xdata and is parsed only after the closing boundary
has arrived. The parts are walked in one pass, the part carrying a
filename is written to a freshly erased sector, and the client receives
a 200 instead of the previous silent close. No segmentation can confuse
this, since the parser only ever sees a complete body.

Locating the closing boundary first also bounds the walk over the parts,
since none can lie beyond it, so the length of the buffer is no longer
the bound and the test for the two trailing dashes is unnecessary.

The walk matches at offsets inside a buffer that is not terminated, so
neither existing helper fits: strcmp() goes on to compare the byte after
the match and is_word_x() demands a separator there. Add strstart() and
strstart_x() for that case, and use strlen_x() for the boundary length.

The firmware upload path still streams, since a megabyte cannot be
buffered, and is untouched.
2026-08-23 18:11:46 -05:00
logicog 025f72c876 Merge pull request #258 from bennydiamond/newline-on-uip-serial-print
Automatically print newline on serial interface
2026-08-22 19:14:45 +02:00
d00f 1d1e33f4d5 sfp: notice when an I2C read fails
sfp_read_reg() waited for the transfer to finish and then read the output
register whatever the outcome, so an address nothing acknowledged came back
as an ordinary byte and no caller could tell it apart from data. The vendor
SDK looks at bit 1 of the control register for exactly this, and we did
not.

A failure now sets sfp_i2c_fail and the read returns 0xff, which is already
the value sfp_apply_quirks() reads as either a failed transfer or a voltage
the spec does not allow, so that test starts being true when it should be.
The insertion path and the sfp command clear the flag first and say so
afterwards, rather than presenting the bytes as though they came from the
module.

What this deliberately does not do is act on the failure. Skipping
sds_config() when the rate read failed is the obvious next step, but a
module that raises the bit spuriously would then never be configured at
all, which is worse than what happens today, and I have no way to judge how
often the bit is right. That decision belongs with someone holding the
board.

It also leaves the other half of the rewrite alone, reading and writing up
to sixteen bytes per transaction. doc/sfp.md describes only the single byte
path and does not name a length field, and guessing at a register I cannot
test is how the last attempt at this function went wrong.

40 bytes of the common segment, 51 of BANK2 and 1 of xdata, nothing in
BANK1 or internal RAM. Built for SWTGW218AS and KP_9000_6XHML_X2 on sdcc
4.5.0. Not tested on hardware: shorting the clock line, as in #342, should
now print the failure line instead of a plausible looking byte.
2026-08-15 23:14:53 +02:00
bloqaudio 0998b7381f machine: add PCB SWTG018AS-V2.1.0 variant of the SWTGW218AS
The SWTGW218AS label covers more than one PCB. On boards with the
SWTG018AS-V2.1.0 silkscreen the SFP module-detect is GPIO38 (no LOS pin
wired) and the LED block is wired differently, including a bi-color SFP
LED (green up to 2.5G, blue at 10G) that the LED-set encoding cannot
express. With the existing MACHINE_SWTGW218AS definition these boards
never detect an SFP module, so an SFP-uplinked switch comes up with no
working uplink.

Add the variant as its own machine define named by the PCB marking,
leaving MACHINE_SWTGW218AS unchanged for boards that match its wiring.
The LED register values are taken from the stock firmware; the PIN_MUX_0
write routes the blue-LED pin to the LED controller, without which no
LED register value can drive it. PIN_MUX_1/2 stay untouched so SFP
detect and i2c remain GPIOs.
2026-08-13 16:19:25 -05:00
donbernhardo 457f117216 Add PCB43 V1.1 and symmetric KP-9000 6XH targets 2026-06-29 20:59:28 +02:00
donbernhardo dd52e8e85e Discard incorrect KP-9000 V1.2 LED mux override 2026-06-29 14:12:31 +02:00
donbernhardo ecf8c999b1 Merge main into KP-9000 PCB revision split 2026-06-29 14:00:22 +02:00
donbernhardo 64a1d252cd Split KP-9000 6XH targets by PCB revision 2026-06-29 13:54:47 +02:00
donbernhardo d3e8698e40 Fix KP-9000-6XHML-X2 LED mux mapping 2026-06-17 21:16:21 +02:00
bennydiamond 7a7ffd3bf8 Automatically print newline on serial interface
For some print_string
2026-06-07 14:52:56 -04:00
27 changed files with 1089 additions and 655 deletions
+3 -1
View File
@@ -53,6 +53,7 @@ create_build_dir:
# Keep machine.c in first position to fail immediately on invalid $MACHINE value # Keep machine.c in first position to fail immediately on invalid $MACHINE value
SRCS = \ SRCS = \
machine.c \ machine.c \
machine_init.c \
cmd_editor.c \ cmd_editor.c \
cmd_parser.c \ cmd_parser.c \
dhcp.c \ dhcp.c \
@@ -138,10 +139,11 @@ $(BUILDDIR)/rtlplayground-$(FILENAME_EXTENSION).bin: $(BUILDDIR)/rtlplayground.i
machine_check: machine_check:
@mkdir -p $(BUILDDIR)/tmp @mkdir -p $(BUILDDIR)/tmp
@set -eo pipefail; \ @set -eo pipefail; \
for MACHINE in `grep -e ' MACHINE_' machine.c | sed -e 's%^.* MACHINE_%%' -e 's%[ ]*//.*$$%%' | sort -u`; \ for MACHINE in `grep -E '^[[:space:]]*(//[[:space:]]*)?#define MACHINE_' machine.h | sed -E 's%^[[:space:]]*(//[[:space:]]*)?#define MACHINE_%%' | awk '{print $$1}' | sort -u`; \
do \ do \
echo "Checking $${MACHINE}"; \ 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.c; \
$(CC) $(CC_FLAGS) -DMACHINE_$${MACHINE} -MMD -o $(BUILDDIR)/tmp/machine_check -c machine_init.c; \
done done
@rm -rf $(BUILDDIR)/tmp @rm -rf $(BUILDDIR)/tmp
+1 -1
View File
@@ -193,7 +193,7 @@ void cmd_edit(void) __banked
// Check whether return was pressed: // Check whether return was pressed:
if (sbuf[l] == '\n' || sbuf[l] == '\r') { if (sbuf[l] == '\n' || sbuf[l] == '\r') {
write_char('\n'); write_char('\n');
cmd_buffer[cmd_line_len] = '\0'; cmd_buffer[cmd_line_len] = NUL;
// write_char('>'); print_string_x(cmd_buffer); write_char('<'); // write_char('>'); print_string_x(cmd_buffer); write_char('<');
// If there is a command we print the prompt after execution // If there is a command we print the prompt after execution
// otherwise immediately because there is nothing to execute // otherwise immediately because there is nothing to execute
+401 -291
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -15,7 +15,7 @@ and sold by Mokerlink.
The device is fully supported: The device is fully supported:
- All 4 2.5GBASE-T RJ45 ports work at 10/100/1000/2500 Mbps - All 4 2.5GBASE-T RJ45 ports work at 10/100/1000/2500 Mbps
- The SFP+ port supports 1G, 2.5G and 10G modules - 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 in machine.h if building yourself or the corresponding pre-compiled binary) - 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. - untested due to missing Hardware: SFP+ ports equipped with 1G or 2.5G SFPs.
### Hardware overview ### Hardware overview
+41 -5
View File
@@ -1,17 +1,36 @@
# Keeplink KP-9000-6XH-X2 # Keeplink KP-9000-6XH-X2 / KP-9000-6XHML-X2
Following is documentation for unmanaged switch marked as `KP-9000-6XH-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. Using SPI clamp in-board is the only method for initial installation.
### Label specifications ### Label specifications
- **Name**: 4X 2.5G RJ45 Port + 2 X 10G SFP+ Port - **Name**: 4X 2.5G RJ45 Port + 2 X 10G SFP+ Port
- **Model**: KP-9000-6XH-X2 - **Model**: KP-9000-6XH-X2 / KP-9000-6XHML-X2
- **Ports**: - **Ports**:
- 4 × RJ45: 10/100/1000/2500 Mbps - 4 × RJ45: 10/100/1000/2500 Mbps
- 2 × SFP+: 1000 / 2500 / 10000 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 ### What works
- All four 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps - All four 2.5GBASE-T RJ45 ports at 10/100/1000/2500 Mbps
@@ -19,7 +38,7 @@ Using SPI clamp in-board is the only method for initial installation.
- LEDs - LEDs
- untested due to missing Hardware: SFP+ ports equipped with 1G or 2.5G SFPs. - untested due to missing Hardware: SFP+ ports equipped with 1G or 2.5G SFPs.
### Hardware overview ### Hardware overview: 2M-PCB43-V2.1
Front side: Front side:
@@ -44,6 +63,24 @@ Bottom
<img src="photos/2M-PCB43-V2.1-unmanaged/2M-PCB43-V2.1-bottom.jpg" width="600" /> <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 ## Reset Button
There's an unpopulated Reset button on the front left side of the PCB. There's an unpopulated Reset button on the front left side of the PCB.
@@ -54,4 +91,3 @@ The front case has already the hole in the metal case, you just have to punch a
## Power supply ## Power supply
Input power is delivered via barell plug, `12V 1A` adapter was provided. Input power is delivered via barell plug, `12V 1A` adapter was provided.
+6 -1
View File
@@ -15,11 +15,12 @@ The following devices have been tested and are fully working:
| Horaco | ZX310S-4T2XT | Yes | [PCB-SL310S-4T2XT-V1.0.0-22273](devices/ZX310S-4T2XT.md) | 2M | 6 | | 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-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 | | Horaco | ZX-SWTG124AS | Yes | [SWTG024AS-v2.0](devices/SWTG024AS.md) | | 4 + 2 |
| Keeplink | KP-9000-6XH-X2 | No | [2M-PCB43-V2.1](devices/KP-9000-6XH-X2.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-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 | | 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 | SWTG024AS | No | [SWTG024AS-v2.0-17452](devices/SWTG024AS.md) | 0.5M | 4 + 2 |
| Lianguo | ZX-SWTGW215AS | Yes | [PCB-SWTG115AS-V2.0](devices/SWTGW215AS.md) | 2M | 5 + 1 | | Lianguo | ZX-SWTGW215AS | Yes | [PCB-SWTG115AS-V2.0](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| ZX-SWTGW218AS | Yes | [SWTG118AS-V2.0-16029](devices/SWTGW218AS.md) | 2M | 8 + 1 |
| Ruiying | RY-4GT-2SX | No | [FG-4GT-2SX_V2.0](devices/FG-4GT-2SX_V2.0.md) | 4M | 4 + 2 | | Ruiying | RY-4GT-2SX | No | [FG-4GT-2SX_V2.0](devices/FG-4GT-2SX_V2.0.md) | 4M | 4 + 2 |
| Sodola | SL-SWTG124AS-D | Yes | [SWTG024AS-v2.0-17452](devices/SWTG024AS.md) | 2M | 4 + 2 | | Sodola | SL-SWTG124AS-D | Yes | [SWTG024AS-v2.0-17452](devices/SWTG024AS.md) | 2M | 4 + 2 |
@@ -29,6 +30,10 @@ The following devices have been tested and are fully working:
| XikeStor | SKS3200-8E1X | Yes | [SWTG118AS-V2.1-17462](devices/SWTGW218AS.md) | 2M | 8 + 1 | | 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 | | 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 Many of the RTL8272/3 devices come in versions with PoE support. The RTLPlayground usually also
+1 -1
View File
@@ -180,7 +180,7 @@ function fillStats() {
td = tr.insertCell(); td.appendChild(document.createTextNode(`${txB[i]}` + t('common_pkts'))); td = tr.insertCell(); td.appendChild(document.createTextNode(`${txB[i]}` + t('common_pkts')));
td = tr.insertCell(); td.appendChild(document.createTextNode(`${rxG[i]}` + t('common_pkts'))); td = tr.insertCell(); td.appendChild(document.createTextNode(`${rxG[i]}` + t('common_pkts')));
td = tr.insertCell(); td.appendChild(document.createTextNode(`${rxB[i]}` + t('common_pkts'))); td = tr.insertCell(); td.appendChild(document.createTextNode(`${rxB[i]}` + t('common_pkts')));
var button = '<button type="button" style="margin: 0 0 0 24px" onclick="getCounters(' + i + ');">' + t('stat_show') + '</button>'; var button = '<button type="button" style="margin: 0 0 0 24px" onclick="getCounters(' + (i + 1) + ');">' + t('stat_show') + '</button>';
td = tr.insertCell(); td.innerHTML = button; td = tr.insertCell(); td.innerHTML = button;
} }
} }
+121 -32
View File
@@ -41,8 +41,17 @@ __xdata uint32_t cont_addr;
// HTTP header properties // HTTP header properties
__xdata uint8_t boundary[72]; __xdata uint8_t boundary[72];
__xdata uint8_t *content_type = 0;
__xdata uint8_t *session = 0; // a client may split the request anywhere, including inside a boundary or a
// part header, so a configuration upload is parsed only once it is complete;
// sized for a full config sector plus the multipart framing around it
#define CONFIG_UPLOAD_BUF (CONFIG_LEN + 384)
__xdata uint8_t config_upload;
__xdata uint8_t config_buf[CONFIG_UPLOAD_BUF];
__xdata uint16_t cfg_pos, cfg_hdr, cfg_body, cfg_end, cfg_last;
__xdata uint8_t cfg_bl;
__xdata uint8_t * __xdata content_type = 0;
__xdata uint8_t * __xdata session = 0;
// Global variables holding POST state // Global variables holding POST state
__xdata uint16_t bindex; // Current index into the boundary __xdata uint16_t bindex; // Current index into the boundary
@@ -54,7 +63,7 @@ __xdata char passwd[21];
__xdata char session_id[SESSION_ID_LENGTH + 1]; __xdata char session_id[SESSION_ID_LENGTH + 1];
__xdata uint8_t authenticated; __xdata uint8_t authenticated;
__xdata uint32_t now; __xdata uint32_t now;
__xdata uint8_t *timeptr; __xdata uint8_t * __xdata timeptr;
__xdata uint32_t last_session_use; __xdata uint32_t last_session_use;
#define TSTATE_NONE 0 #define TSTATE_NONE 0
@@ -77,6 +86,7 @@ inline uint8_t is_separator(uint8_t c)
void httpd_init(void) __banked void httpd_init(void) __banked
{ {
config_upload = 0; // xdata is not zeroed by the startup code
__xdata struct httpd_state * __xdata s = &(uip_conn->appstate); __xdata struct httpd_state * __xdata s = &(uip_conn->appstate);
// Start listening to port 80 // Start listening to port 80
uip_listen(HTONS(80)); uip_listen(HTONS(80));
@@ -109,8 +119,8 @@ bool is_word(__xdata uint8_t *xdata_str_p, __code uint8_t * __xdata code_str_p)
u = *xdata_str_p++; u = *xdata_str_p++;
c = *code_str_p++; c = *code_str_p++;
if (c == '\0') { if (c == NUL) {
if (u != '\0' && u != ' ' && u != '\t' && u != ':' && u != '?' && u != '=' && u != '\n' && u != '\r') if (u != NUL && u != ' ' && u != '\t' && u != ':' && u != '?' && u != '=' && u != '\n' && u != '\r')
return false; return false;
return true; return true;
} }
@@ -130,8 +140,8 @@ bool is_url_word_x(__xdata uint8_t *uri_str_p, __xdata uint8_t *src_str_p)
u = *uri_str_p++; u = *uri_str_p++;
s = *src_str_p++; s = *src_str_p++;
if (s == '\0') { if (s == NUL) {
if (u != '\0' && u != ' ' && u != '\t' && u != ':' && u != '?' && u != '=' && u != '\n' && u != '\r') if (u != NUL && u != ' ' && u != '\t' && u != ':' && u != '?' && u != '=' && u != '\n' && u != '\r')
return false; return false;
return true; return true;
} }
@@ -173,9 +183,9 @@ bool is_word_x(__xdata uint8_t *lhs_str_p, __xdata uint8_t *rhs_str_p)
u = *lhs_str_p++; u = *lhs_str_p++;
c = *rhs_str_p++; c = *rhs_str_p++;
if (c == '\0') { if (c == NUL) {
/* ';' separates cookies in a Cookie header, so it ends a value too. */ /* ';' separates cookies in a Cookie header, so it ends a value too. */
if (u != '\0' && u != ' ' && u != '\t' && u != ':' && u != '?' && u != '=' && u != '\n' && u != '\r' && u != ';') if (u != NUL && u != ' ' && u != '\t' && u != ':' && u != '?' && u != '=' && u != '\n' && u != '\r' && u != ';')
return false; return false;
return true; return true;
} }
@@ -241,7 +251,7 @@ __xdata uint8_t *skip_boundary(__xdata uint8_t *p)
} }
__xdata uint8_t *scan_header(__xdata uint8_t *p) __xdata uint8_t *scan_header(__xdata uint8_t * __xdata p)
{ {
content_type = 0; content_type = 0;
session = 0; session = 0;
@@ -300,10 +310,12 @@ __xdata uint8_t *scan_header(__xdata uint8_t *p)
return p; return p;
} }
/*
void gen_random_bytes(__xdata uint8_t *b, uint8_t bytes) * Generate random HEX-chars at the buffer location.
*/
void gen_random_hex_chars(__xdata uint8_t * b, __xdata uint8_t bytes)
{ {
__xdata uint8_t i = 0; uint8_t i = 0;
while (bytes) { while (bytes) {
if (!i) if (!i)
get_random_32(); get_random_32();
@@ -315,6 +327,65 @@ void gen_random_bytes(__xdata uint8_t *b, uint8_t bytes)
} }
/* 0: body incomplete, 1: configuration stored, 2: malformed */
static uint8_t config_take(void)
{
cfg_bl = strlen_x(boundary);
// the body is complete once the closing boundary has arrived
cfg_last = 0;
while (1) {
if (cfg_last + cfg_bl + 1 >= write_len)
return 0;
if (strstart_x(&config_buf[cfg_last], boundary)
&& strstart(&config_buf[cfg_last + cfg_bl], "--"))
break;
cfg_last++;
}
// every part lies ahead of the closing boundary, so it bounds the walk
cfg_pos = 0;
while (cfg_pos < cfg_last) {
if (!strstart_x(&config_buf[cfg_pos], boundary)) {
cfg_pos++;
continue;
}
cfg_hdr = cfg_pos + cfg_bl;
cfg_body = cfg_hdr;
while (1) {
if (cfg_body + 3 >= cfg_last)
return 2;
if (strstart(&config_buf[cfg_body], "\r\n\r\n"))
break;
cfg_body++;
}
cfg_end = cfg_body;
cfg_body += 4;
// reaching cfg_last is a match: the last part ends at the closing boundary
while (cfg_end < cfg_last && !strstart_x(&config_buf[cfg_end], boundary))
cfg_end++;
while (cfg_hdr + 8 < cfg_body) {
// the part carrying a filename holds the configuration
if (strstart(&config_buf[cfg_hdr], "filename")) {
// the payload plus its terminator must fit the sector
if (cfg_end - cfg_body + 1 > CONFIG_LEN)
return 2;
config_buf[cfg_end] = 0;
flash_region.addr = CONFIG_START;
flash_sector_erase();
flash_region.addr = CONFIG_START;
flash_region.len = cfg_end - cfg_body + 1;
flash_write_bytes(config_buf + cfg_body);
return 1;
}
cfg_hdr++;
}
cfg_pos = cfg_end;
}
return 2;
}
/* /*
* Reads post data from the http stream and writes it into flash memory * Reads post data from the http stream and writes it into flash memory
* Input: the current position in the TCP buffer (uip_appdata) * Input: the current position in the TCP buffer (uip_appdata)
@@ -418,10 +489,10 @@ void handle_post(void)
// Find end of request path // Find end of request path
while (*p && !is_separator(*p)) while (*p && !is_separator(*p))
p++; p++;
*p++ = '\0'; *p++ = NUL;
// Find end of request header // Find end of request header
boundary[0] ='\0'; boundary[0] =NUL;
p = scan_header(p); p = scan_header(p);
dbg_string("Boundary: >"); dbg_string_x(boundary); dbg_string("<\n"); dbg_string("Boundary: >"); dbg_string_x(boundary); dbg_string("<\n");
if (!*p || !content_type) { if (!*p || !content_type) {
@@ -437,6 +508,7 @@ void handle_post(void)
return; return;
} }
print_string("Firmware upload started."); print_string("Firmware upload started.");
config_upload = 0;
uptr = FIRMWARE_UPLOAD_START; uptr = FIRMWARE_UPLOAD_START;
verify_crc = 1; verify_crc = 1;
max_upload = 1024576; max_upload = 1024576;
@@ -445,12 +517,10 @@ void handle_post(void)
send_unauthorized(); send_unauthorized();
return; return;
} }
dbg_string("Configuration upload, erasing config mem!\n"); dbg_string("Configuration upload\n");
uptr = CONFIG_START;
verify_crc = 0; verify_crc = 0;
max_upload = 2048; config_upload = 1;
flash_region.addr = CONFIG_START; write_len = 0;
flash_sector_erase();
} }
// Check for other POST requests, which are not multipart, below // Check for other POST requests, which are not multipart, below
} else { } else {
@@ -481,11 +551,11 @@ void handle_post(void)
if (is_url_word_x(p, passwd)) { if (is_url_word_x(p, passwd)) {
dbg_string("Password accepted!\n"); dbg_string("Password accepted!\n");
read_reg_timer(&last_session_use); read_reg_timer(&last_session_use);
gen_random_bytes(session_id, SESSION_ID_LENGTH); gen_random_hex_chars(session_id, SESSION_ID_LENGTH);
session_id[SESSION_ID_LENGTH] = '\0'; session_id[SESSION_ID_LENGTH] = NUL;
slen = strtox(outbuf, "HTTP/1.1 302 Found\r\nConnection: close\r\nLocation: index.html\r\n" \ slen = strtox(outbuf, "HTTP/1.1 302 Found\r\nConnection: close\r\nLocation: index.html\r\n" \
"Set-Cookie: session="); "Set-Cookie: session=");
for (register uint8_t i = 0; i < SESSION_ID_LENGTH; i++) for (uint8_t i = 0; i < SESSION_ID_LENGTH; i++)
outbuf[slen++] = session_id[i]; outbuf[slen++] = session_id[i];
slen += strtox(outbuf + slen, "; SameSite=Strict\r\n\r\n"); slen += strtox(outbuf + slen, "; SameSite=Strict\r\n\r\n");
} else { } else {
@@ -504,6 +574,32 @@ void handle_post(void)
send_bad_request(); send_bad_request();
return; return;
} }
if (config_upload) {
cfg_pos = uip_len - (p - uip_appdata);
if (write_len + cfg_pos >= CONFIG_UPLOAD_BUF) {
print_string("Configuration too large, aborting.\n");
config_upload = 0;
s->tstate = TSTATE_NONE;
send_bad_request();
return;
}
memcpy(config_buf + write_len, p, cfg_pos);
write_len += cfg_pos;
uint8_t taken = config_take();
if (!taken) {
s->tstate = TSTATE_MULTIPART;
return;
}
config_upload = 0;
s->tstate = TSTATE_NONE;
if (taken == 2) {
send_bad_request();
return;
}
slen = strtox(outbuf, "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n");
return;
}
// We skip the intial parts as part of the header // We skip the intial parts as part of the header
do { do {
p = skip_boundary(p); p = skip_boundary(p);
@@ -642,7 +738,7 @@ void httpd_appcall(void)
__xdata uint8_t *q = p; __xdata uint8_t *q = p;
while (*p && !is_separator(*p)) while (*p && !is_separator(*p))
p++; p++;
*p = '\0'; *p = NUL;
dbg_string_x(q); dbg_string_x(q);
dbg_char('\n'); dbg_char('\n');
@@ -664,16 +760,9 @@ void httpd_appcall(void)
parse_short(q + 15); parse_short(q + 15);
send_vlan(short_parsed); send_vlan(short_parsed);
} else if (is_word(q, "/counters.json")) { } else if (is_word(q, "/counters.json")) {
/* The port is one raw character of the request line and
* indexes a nine entry table, so bound it here instead
* of trusting the client to have sent a digit. Anything
* below '0' wraps well past eight, so the one test
* covers both ends. */
uint8_t cport = q[20] - '0'; uint8_t cport = q[20] - '0';
if (cport > 8) if (send_counters(cport))
send_bad_request(); send_bad_request();
else
send_counters(cport);
} else if (is_word(q, "/eee.json")) { } else if (is_word(q, "/eee.json")) {
send_eee(); send_eee();
} else if (is_word(q, "/bandwidth.json")) { } else if (is_word(q, "/bandwidth.json")) {
+37 -42
View File
@@ -157,14 +157,14 @@ void sfr_data_to_html(void)
} }
void reg_to_html(register uint16_t reg) void reg_to_html(uint16_t reg)
{ {
reg_read_m(reg); reg_read_m(reg);
sfr_data_to_html(); sfr_data_to_html();
} }
void reg_to_html_long(register uint16_t reg) void reg_to_html_long(uint16_t reg)
{ {
reg_read_m(reg); reg_read_m(reg);
byte_to_html(sfr_data[0]); byte_to_html(sfr_data[0]);
@@ -177,10 +177,12 @@ void reg_to_html_long(register uint16_t reg)
void send_sfp_info(uint8_t sfp) void send_sfp_info(uint8_t sfp)
{ {
// This loops over the Vendor-name, Vendor OUI, Vendor PN and Vendor rev ASCII fields // This loops over the Vendor-name, Vendor OUI, Vendor PN and Vendor rev ASCII fields
for (uint8_t i = 20; i < 60; i++) { for (uint8_t i = 16; i < 64; i++) {
if (i >= 36 && i < 40) // Skip Non-ASCII codes if (!(i & 0xf))
sfp_read_block(sfp, i, 16);
if (i < 20 || i >= 60 || (i >= 36 && i < 40)) // Skip Non-ASCII codes
continue; continue;
uint8_t c = sfp_read_reg(sfp, i); uint8_t c = sfp_buf[i & 0xf];
if (c && c != 0xa0) // a0 is the byte read from a non-existant I2C EEPROM if (c && c != 0xa0) // a0 is the byte read from a non-existant I2C EEPROM
char_to_html(c); char_to_html(c);
} }
@@ -193,32 +195,10 @@ void sfp_send_data(uint8_t slot, uint8_t reg, uint8_t len)
if (len > 16) if (len > 16)
return; return;
if (reg & 0x80) { // Configure SFP readings address (0x51) as I2C device address sfp_read_block(slot, reg, len);
reg &= 0x7f;
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | (len - 1) & 0xf, 0x51 >> 5, (0x51 << 3) & 0xff);
} else {
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | (len - 1) & 0xf, 0x50 >> 5, (0x50 << 3) & 0xff);
}
reg_read_m(RTL837X_REG_I2C_CTRL); for (uint8_t i = 0; i < len; i++)
sfr_mask_data(1, 0xfc, i2c_bus_from_scl_pin(machine.sfp_port[slot].i2c.scl) << 5 | i2c_bus_from_sda_pin(machine.sfp_port[slot].i2c.sda) << 2); byte_to_html(sfp_buf[i]);
reg_write_m(RTL837X_REG_I2C_CTRL);
REG_WRITE(RTL837X_REG_I2C_IN, 0, 0, 0, reg);
// Execute I2C Read
reg_bit_set(RTL837X_REG_I2C_CTRL, 0);
// Wait for execution to finish
do {
reg_read_m(RTL837X_REG_I2C_CTRL);
} while (sfr_data[3] & 0x1);
for (uint8_t i = 0; i < len; i++) {
if (!(i & 0x3))
reg_read_m(RTL837X_REG_I2C_OUT + i);
byte_to_html(sfr_data[3 - (i & 0x3)]);
}
} }
@@ -309,17 +289,26 @@ void send_vlan(uint16_t vlan)
slen += strtox(outbuf + slen, "\"}"); slen += strtox(outbuf + slen, "\"}");
} }
/* Send counters
void send_counters(char port) * Only accepts physical port 1..9.
* Returns an error if the port physical don't exists.
*/
bool send_counters(uint8_t phys_port)
{ {
dbg_string("send_counters called: "); dbg_byte(port); dbg_char('\n'); uint8_t phys_port_idx = phys_port - 1;
if (phys_port_idx > 8)
goto err;
uint8_t log_port = machine.phys_to_log_port[phys_port_idx];
if (log_port == 0)
goto err;
dbg_string("send_counters called: "); dbg_byte(phys_port_idx); dbg_char('\n');
slen = strtox(outbuf, HTTP_RESPONCE_JSON); slen = strtox(outbuf, HTTP_RESPONCE_JSON);
dbg_string("sending counters\n"); dbg_string("sending counters\n"); dbg_byte(phys_port_idx);
dbg_byte(port);
uint8_t i = machine.phys_to_log_port[port]; char_to_html('[');
slen += strtox(outbuf + slen, "[");
for (uint8_t counter = 0; counter < 0x37; counter++) { for (uint8_t counter = 0; counter < 0x37; counter++) {
STAT_GET(counter, i); STAT_GET(counter, log_port);
slen += strtox(outbuf + slen, "\"0x"); slen += strtox(outbuf + slen, "\"0x");
reg_to_html(RTL837X_STAT_V_HIGH); reg_to_html(RTL837X_STAT_V_HIGH);
reg_to_html_long(RTL837X_STAT_V_LOW); reg_to_html_long(RTL837X_STAT_V_LOW);
@@ -328,6 +317,12 @@ void send_counters(char port)
char_to_html(','); char_to_html(',');
} }
char_to_html(']'); char_to_html(']');
return false;
err:
dbg_string("Error: counters: phy_port_idx don't exists\n");
return true;
} }
@@ -702,13 +697,13 @@ void send_status(void)
sfp_send_data(sfp, 238, 1); sfp_send_data(sfp, 238, 1);
} }
slen += strtox(outbuf + slen,"\",\"sfp_vendor\":\""); slen += strtox(outbuf + slen,"\",\"sfp_vendor\":\"");
for (register uint8_t s = 0; s < 16 && sfp_module_vendor[sfp][s]; s++) for (uint8_t s = 0; s < 16 && sfp_module_vendor[sfp][s]; s++)
outbuf[slen++] = sfp_module_vendor[sfp][s]; outbuf[slen++] = sfp_module_vendor[sfp][s];
slen += strtox(outbuf + slen,"\",\"sfp_model\":\""); slen += strtox(outbuf + slen,"\",\"sfp_model\":\"");
for (register uint8_t s = 0; s < 16 && sfp_module_model[sfp][s]; s++) for (uint8_t s = 0; s < 16 && sfp_module_model[sfp][s]; s++)
outbuf[slen++] = sfp_module_model[sfp][s]; outbuf[slen++] = sfp_module_model[sfp][s];
slen += strtox(outbuf + slen,"\",\"sfp_serial\":\""); slen += strtox(outbuf + slen,"\",\"sfp_serial\":\"");
for (register uint8_t s = 0; s < 16 && sfp_module_serial[sfp][s]; s++) for (uint8_t s = 0; s < 16 && sfp_module_serial[sfp][s]; s++)
outbuf[slen++] = sfp_module_serial[sfp][s]; outbuf[slen++] = sfp_module_serial[sfp][s];
slen += strtox(outbuf + slen,"\",\"sfp_los\":"); slen += strtox(outbuf + slen,"\",\"sfp_los\":");
if (machine.sfp_port[sfp].pin_los == GPIO_NA) { if (machine.sfp_port[sfp].pin_los == GPIO_NA) {
@@ -822,7 +817,7 @@ found_end:
if (valid_len > (TCP_OUTBUF_SIZE - slen)) { if (valid_len > (TCP_OUTBUF_SIZE - slen)) {
cont_len = valid_len - (TCP_OUTBUF_SIZE - slen); cont_len = valid_len - (TCP_OUTBUF_SIZE - slen);
valid_len = TCP_OUTBUF_SIZE - slen; valid_len = TCP_OUTBUF_SIZE - slen;
cont_addr = valid_len; cont_addr = CONFIG_START + valid_len;
} }
flash_region.addr = CONFIG_START; flash_region.addr = CONFIG_START;
+3 -1
View File
@@ -1,7 +1,9 @@
#ifndef __PAGE_IMPL_H__ #ifndef __PAGE_IMPL_H__
#define __PAGE_IMPL_H__ #define __PAGE_IMPL_H__
void send_counters(char port); #include <stdbool.h>
bool send_counters(uint8_t phys_port);
void send_status(void); void send_status(void);
void send_vlan(uint16_t vlan); void send_vlan(uint16_t vlan);
void send_basic_info(void); void send_basic_info(void);
+1 -1
View File
@@ -213,7 +213,7 @@ uint8_t flash_read_status(void)
* Reads bulk data of length len from the flash memory starging at address src * Reads bulk data of length len from the flash memory starging at address src
* and writes the data into a buffer pointed to by dst in XMEM * and writes the data into a buffer pointed to by dst in XMEM
*/ */
void flash_read_bulk(register __xdata uint8_t *dst, __xdata uint32_t src, register uint16_t len) void flash_read_bulk(__xdata uint8_t *dst, __xdata uint32_t src, uint16_t len)
{ {
short status; short status;
do { do {
+64 -104
View File
@@ -5,9 +5,23 @@
#include "rtl837x_regs.h" #include "rtl837x_regs.h"
#include "rtl837x_common.h" #include "rtl837x_common.h"
#ifdef MACHINE_KP_9000_6XHML_X2 #if defined(MACHINE_KP_9000_6XHML_X2) || \
defined(MACHINE_KP_9000_6XH_X2_V1_1) || \
defined(MACHINE_KP_9000_6XHML_X2_V1_1) || \
defined(MACHINE_KP_9000_6XH_X2_V1_2) || \
defined(MACHINE_KP_9000_6XHML_X2_V1_2)
__code const struct machine machine = { __code const struct machine machine = {
#if defined(MACHINE_KP_9000_6XH_X2_V1_1)
.machine_name = "keepLink KP-9000-6XH V1.1",
#elif defined(MACHINE_KP_9000_6XHML_X2_V1_1)
.machine_name = "keepLink KP-9000-6XHML V1.1",
#elif defined(MACHINE_KP_9000_6XH_X2_V1_2)
.machine_name = "keepLink KP-9000-6XH V1.2",
#elif defined(MACHINE_KP_9000_6XHML_X2_V1_2)
.machine_name = "keepLink KP-9000-6XHML V1.2",
#else
.machine_name = "keepLink KP-9000-6XHML-X2", .machine_name = "keepLink KP-9000-6XHML-X2",
#endif
.isRTL8373 = 0, .isRTL8373 = 0,
.min_port = 3, .min_port = 3,
.max_port = 8, .max_port = 8,
@@ -42,8 +56,6 @@ __code const struct machine machine = {
}, },
}; };
void machine_custom_init(void) { }
#elif defined MACHINE_KP_9000_6XH_X #elif defined MACHINE_KP_9000_6XH_X
__code const struct machine machine = { __code const struct machine machine = {
.machine_name = "keepLink KP-9000-6XH-X", .machine_name = "keepLink KP-9000-6XH-X",
@@ -72,11 +84,15 @@ __code const struct machine machine = {
}, },
}; };
void machine_custom_init(void) { } #elif defined(MACHINE_KP_9000_6XH_X2) || defined(MACHINE_KP_9000_6XH_X2_V2_1) || defined(MACHINE_KP_9000_6XHML_X2_V2_1)
#elif defined MACHINE_KP_9000_6XH_X2
__code const struct machine machine = { __code const struct machine machine = {
#if defined(MACHINE_KP_9000_6XHML_X2_V2_1)
.machine_name = "keepLink KP-9000-6XHML V2.1",
#elif defined(MACHINE_KP_9000_6XH_X2_V2_1)
.machine_name = "keepLink KP-9000-6XH-X2 V2.1",
#else
.machine_name = "keepLink KP-9000-6XH-X2", .machine_name = "keepLink KP-9000-6XH-X2",
#endif
.isRTL8373 = 0, .isRTL8373 = 0,
.min_port = 3, .min_port = 3,
.max_port = 8, .max_port = 8,
@@ -122,10 +138,6 @@ __code const struct machine machine = {
}, },
}; };
void machine_custom_init(void) {
reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6);
}
#elif defined MACHINE_KP_9000_9XH_X_EU #elif defined MACHINE_KP_9000_9XH_X_EU
__code const struct machine machine = { __code const struct machine machine = {
.machine_name = "keepLink KP-9000-9XH-X-EU", .machine_name = "keepLink KP-9000-9XH-X-EU",
@@ -151,8 +163,6 @@ __code const struct machine machine = {
}, },
}; };
void machine_custom_init(void) { }
#elif defined MACHINE_KP_9000_9XHML_X_V2_2 #elif defined MACHINE_KP_9000_9XHML_X_V2_2
__code const struct machine machine = { __code const struct machine machine = {
.machine_name = "keepLink KP-9000-9XHML-X V2.2", .machine_name = "keepLink KP-9000-9XHML-X V2.2",
@@ -204,8 +214,6 @@ __code const struct machine machine = {
}, },
}; };
void machine_custom_init(void) { }
#elif defined MACHINE_KP_9000_9XHML_X_V3_1 #elif defined MACHINE_KP_9000_9XHML_X_V3_1
__code const struct machine machine = { __code const struct machine machine = {
.machine_name = "keepLink KP-9000-9XHML-X V3.1", .machine_name = "keepLink KP-9000-9XHML-X V3.1",
@@ -241,8 +249,6 @@ __code const struct machine machine = {
0x1a, 0x19, 0x1d, 0x1e, 0x1c, 0x1d, 0x20, 0x21}, 0x1a, 0x19, 0x1d, 0x1e, 0x1c, 0x1d, 0x20, 0x21},
}; };
void machine_custom_init(void) { }
#elif defined MACHINE_SWGT024_V2_0_MANAGED #elif defined MACHINE_SWGT024_V2_0_MANAGED
__code const struct machine machine = { __code const struct machine machine = {
.machine_name = "SWGT024 V2.0 Managed", .machine_name = "SWGT024 V2.0 Managed",
@@ -284,8 +290,6 @@ __code const struct machine machine = {
}, },
}; };
void machine_custom_init(void) { }
#elif defined MACHINE_SWGT024_V2_0_UNMANAGED #elif defined MACHINE_SWGT024_V2_0_UNMANAGED
__code const struct machine machine = { __code const struct machine machine = {
.machine_name = "SWGT024 V2.0 Unmanaged", .machine_name = "SWGT024 V2.0 Unmanaged",
@@ -327,8 +331,6 @@ __code const struct machine machine = {
}, },
}; };
void machine_custom_init(void) { }
#elif defined MACHINE_SWTG018AS_A_V_2_0 #elif defined MACHINE_SWTG018AS_A_V_2_0
__code const struct machine machine = { __code const struct machine machine = {
.machine_name = "SWTG018AS-A V2.0", .machine_name = "SWTG018AS-A V2.0",
@@ -368,8 +370,6 @@ __code const struct machine machine = {
0x1d, 0x20, 0x21 }, 0x1d, 0x20, 0x21 },
}; };
void machine_custom_init(void) { }
#elif defined MACHINE_HG0402XG_V1_1 #elif defined MACHINE_HG0402XG_V1_1
__code const struct machine machine = { __code const struct machine machine = {
.machine_name = "HG0402XG V1.1", .machine_name = "HG0402XG V1.1",
@@ -408,8 +408,6 @@ __code const struct machine machine = {
}, },
}; };
void machine_custom_init(void) { }
#elif defined MACHINE_SWTGW218AS #elif defined MACHINE_SWTGW218AS
__code const struct machine machine = { __code const struct machine machine = {
@@ -443,7 +441,48 @@ __code const struct machine machine = {
}, },
}; };
void machine_custom_init(void) { } #elif defined MACHINE_PCB_SWTG018AS_V2_1_0 // Sold as Sodola SL902 / Horaco "SWTGW218AS"; the SWTGW218AS label also covers other PCBs with different SFP and LED wiring (see MACHINE_SWTGW218AS)
__code const struct machine machine = {
.machine_name = "SWTGW218AS (SWTG018AS-V2.1.0)",
.isRTL8373 = 1,
.mac_flash_offset = 0x1FC000,
.min_port = 0,
.max_port = 8,
.n_sfp = 1,
.log_to_phys_port = {1, 2, 3, 4, 5, 6, 7, 8, 9},
.phys_to_log_port = {0, 1, 2, 3, 4, 5, 6, 7, 8},
.is_sfp = {0, 0, 0, 0, 0, 0, 0, 0, 1},
.sfp_port[0].pin_detect = GPIO38, // pulled low on module insert
.sfp_port[0].pin_los = GPIO_NA, // no LOS pin wired
.sfp_port[0].pin_tx_disable = GPIO_NA,
.sfp_port[0].sds = 1,
.sfp_port[0].i2c = { .sda = GPIO39_I2C_SDA4, .scl = GPIO40_I2C_SCL3_MDC1 },
.reset_pin = GPIO54_ACL_BIT2_EN,
.high_leds = { .mux = LED_27 | LED_28_SYS | LED_29, .enable = LED_28_SYS | LED_29 },
.port_led_set = { 0, 0, 0, 0, 0, 0, 0, 0, 1},
// LED wiring matches the SWTG018AS-A V2.0 (same PCB family)
.led_sets = {
{ /* RJ45: First LED, yellow, second LED: green */
LEDS_2G5 | LEDS_LINK,
LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT,
0,
0,
}, { /* SFP set (superseded by the raw register override in machine_custom_init) */
LEDS_2G5 | LEDS_1G | LEDS_100M | LEDS_10M | LEDS_LINK | LEDS_ACT | LEDS_10G,
0,
0,
0,
}},
.led_mux_custom = 1,
.led_mux = { 0x00, 0x01, 0x04, 0x05, 0x08, // 65e0
0x09, 0x0c, 0x09, 0x0d, 0x10, // 65e4
0x11, 0x0e, 0x14, 0x11, 0x12, // 65e8
0x15, 0x15, 0x16, 0x18, 0x19, // 65ec
0x1a, 0x19, 0x1d, 0x1e, 0x1c, // 65f0
0x1d, 0x20, 0x21 },
};
#elif defined MACHINE_LIANGUO_ZX_SWTGW215AS // Has PCB branded PCB-SWTG115AS-V2.0 but is labeled and reports as a ZX-SWTGW215AS, seems to be identical to the "real" ZX-SWTGW215AS except for the LEDs #elif defined MACHINE_LIANGUO_ZX_SWTGW215AS // Has PCB branded PCB-SWTG115AS-V2.0 but is labeled and reports as a ZX-SWTGW215AS, seems to be identical to the "real" ZX-SWTGW215AS except for the LEDs
__code const struct machine machine = { __code const struct machine machine = {
.machine_name = "Lianguo ZX-SWTGW215AS", .machine_name = "Lianguo ZX-SWTGW215AS",
@@ -476,8 +515,6 @@ __code const struct machine machine = {
.led_mux_custom = 0, .led_mux_custom = 0,
}; };
void machine_custom_init(void) { }
#elif defined MACHINE_DEFAULT_8C_1SFP #elif defined MACHINE_DEFAULT_8C_1SFP
__code const struct machine machine = { __code const struct machine machine = {
.machine_name = "8+1 SFP Port Switch", .machine_name = "8+1 SFP Port Switch",
@@ -503,8 +540,6 @@ __code const struct machine machine = {
}, },
}; };
void machine_custom_init(void) { }
#elif defined MACHINE_TRENDNET_TEG_S562 #elif defined MACHINE_TRENDNET_TEG_S562
__code const struct machine machine = { __code const struct machine machine = {
.machine_name = "Trendnet TEG-S562", .machine_name = "Trendnet TEG-S562",
@@ -544,8 +579,6 @@ __code const struct machine machine = {
}; };
void machine_custom_init(void) { }
#elif defined(MACHINE_PCB_K0402WS_V3) || defined(MACHINE_HI_K0402WS) // Sold as a variety of devices, see doc/ #elif defined(MACHINE_PCB_K0402WS_V3) || defined(MACHINE_HI_K0402WS) // Sold as a variety of devices, see doc/
__code const struct machine machine = { __code const struct machine machine = {
.machine_name = "PCB-K0402WS-V3.0", .machine_name = "PCB-K0402WS-V3.0",
@@ -592,10 +625,6 @@ __code const struct machine machine = {
}, },
}; };
void machine_custom_init(void) {
reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6);
}
#elif defined MACHINE_K0501W_V2_0 #elif defined MACHINE_K0501W_V2_0
__code const struct machine machine = { __code const struct machine machine = {
.machine_name = "K0501W V2.0", .machine_name = "K0501W V2.0",
@@ -630,8 +659,6 @@ __code const struct machine machine = {
}, },
}; };
void machine_custom_init(void) { }
#elif defined MACHINE_ZX310S_4T2XH #elif defined MACHINE_ZX310S_4T2XH
__code const struct machine machine = { __code const struct machine machine = {
.machine_name = "ZX310S-4T2XH", .machine_name = "ZX310S-4T2XH",
@@ -675,8 +702,6 @@ __code const struct machine machine = {
}, },
}; };
void machine_custom_init(void) { }
#elif defined MACHINE_STEAMEMO_IG204_V1 #elif defined MACHINE_STEAMEMO_IG204_V1
__code const struct machine machine = { __code const struct machine machine = {
.machine_name = "Steamemo IG204 V1", .machine_name = "Steamemo IG204 V1",
@@ -727,8 +752,6 @@ __code const struct machine machine = {
}, },
}; };
void machine_custom_init(void) { }
#elif defined MACHINE_HI_K0801WS #elif defined MACHINE_HI_K0801WS
__code const struct machine machine = { __code const struct machine machine = {
.machine_name = "Hi-Source HI-k0801WS", .machine_name = "Hi-Source HI-k0801WS",
@@ -778,8 +801,6 @@ __code const struct machine machine = {
}, },
}; };
void machine_custom_init(void) { }
#elif defined MACHINE_FNS1200P #elif defined MACHINE_FNS1200P
__code const struct machine machine = { __code const struct machine machine = {
.machine_name = "FNS-1200P", .machine_name = "FNS-1200P",
@@ -835,11 +856,6 @@ __code const struct machine machine = {
}, },
}; };
void machine_custom_init(void)
{
reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6);
}
#elif defined MACHINE_PCB_SWTG024AS_A_2_0_1 #elif defined MACHINE_PCB_SWTG024AS_A_2_0_1
__code const struct machine machine = { __code const struct machine machine = {
@@ -889,14 +905,6 @@ __code const struct machine machine = {
}, },
}; };
void machine_custom_init(void)
{
reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6);
reg_bit_set(RTL837X_REG_LED_MODE, 17);
reg_bit_clear(RTL837X_REG_LED_MODE, 9);
reg_bit_clear(RTL837X_REG_LED_MODE, 7);
}
#elif defined MACHINE_SWTG024AS_A_2_0_1_5C_1SFP #elif defined MACHINE_SWTG024AS_A_2_0_1_5C_1SFP
__code const struct machine machine = { __code const struct machine machine = {
.machine_name = "SWTG024AS-A-V2.0.1-5C-1SFP", .machine_name = "SWTG024AS-A-V2.0.1-5C-1SFP",
@@ -940,25 +948,6 @@ __code const struct machine machine = {
}, },
}; };
void machine_custom_init(void)
{
uint16_t pval;
reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6);
reg_bit_set(RTL837X_REG_LED_MODE, 17);
reg_bit_clear(RTL837X_REG_LED_MODE, 9);
reg_bit_clear(RTL837X_REG_LED_MODE, 7);
// OEM firmware sets these companion SDS0 polarity bits for the RTL8221B.
sds_read(0, 0, 0);
pval = SFR_DATA_U16;
sds_write_v(0, 0, 0, pval | 0x100);
sds_read(0, 6, 2);
pval = SFR_DATA_U16;
sds_write_v(0, 6, 2, pval | 0x4000);
}
#elif defined MACHINE_SWTG024AS_V2_0 #elif defined MACHINE_SWTG024AS_V2_0
__code const struct machine machine = { __code const struct machine machine = {
.machine_name = "SWTG024AS-V2.0", .machine_name = "SWTG024AS-V2.0",
@@ -1002,25 +991,6 @@ __code const struct machine machine = {
}, },
}; };
void machine_custom_init(void)
{
uint16_t pval;
reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6);
reg_bit_set(RTL837X_REG_LED_MODE, 17);
reg_bit_clear(RTL837X_REG_LED_MODE, 9);
reg_bit_clear(RTL837X_REG_LED_MODE, 7);
// OEM firmware sets these companion SDS0 polarity bits for the RTL8221B.
sds_read(0, 0, 0);
pval = SFR_DATA_U16;
sds_write_v(0, 0, 0, pval | 0x100);
sds_read(0, 6, 2);
pval = SFR_DATA_U16;
sds_write_v(0, 6, 2, pval | 0x4000);
}
#elif defined MACHINE_ZX310S_4T2XT #elif defined MACHINE_ZX310S_4T2XT
__code const struct machine machine = { __code const struct machine machine = {
.machine_name = "ZX310S_4T2XT", .machine_name = "ZX310S_4T2XT",
@@ -1058,12 +1028,6 @@ __code const struct machine machine = {
}, },
}; };
void machine_custom_init(void) {
// For this device, the reset value of RTL837X_PIN_MUX_0 is 0x30000000,
// which would disables all LEDS, enable them manually:
REG_SET(RTL837X_PIN_MUX_0, 0x30db68bf);
}
#elif defined MACHINE_FG_4GT_2SX_V2_0 #elif defined MACHINE_FG_4GT_2SX_V2_0
__code const struct machine machine = { __code const struct machine machine = {
.machine_name = "FG-4GT-2SX_V2.0", .machine_name = "FG-4GT-2SX_V2.0",
@@ -1130,10 +1094,6 @@ __code const struct machine machine = {
}, },
}; };
void machine_custom_init(void) {
REG_SET(RTL837X_REG_LED_GLB_IO_EN, 0x7624155b);
}
#else #else
#error "Please select a machine type in machine.h" #error "Please select a machine type in machine.h"
#endif #endif
+13 -2
View File
@@ -6,9 +6,19 @@
/* /*
* Select your machine type below * Select your machine type below
*/ */
// Legacy KP-9000 4+2 targets. Prefer the PCB-revision-specific targets below.
// #define MACHINE_KP_9000_6XHML_X2 // #define MACHINE_KP_9000_6XHML_X2
// #define MACHINE_KP_9000_6XH_X
// #define MACHINE_KP_9000_6XH_X2 // #define MACHINE_KP_9000_6XH_X2
// KP-9000 4+2 targets by PCB silkscreen revision.
// #define MACHINE_KP_9000_6XH_X2_V1_1
// #define MACHINE_KP_9000_6XHML_X2_V1_1
// #define MACHINE_KP_9000_6XH_X2_V1_2
// #define MACHINE_KP_9000_6XHML_X2_V1_2
// #define MACHINE_KP_9000_6XH_X2_V2_1
// #define MACHINE_KP_9000_6XHML_X2_V2_1
// #define MACHINE_KP_9000_6XH_X
// #define MACHINE_KP_9000_9XH_X_EU // #define MACHINE_KP_9000_9XH_X_EU
// #define MACHINE_KP_9000_9XHML_X_V2_2 // #define MACHINE_KP_9000_9XHML_X_V2_2
// #define MACHINE_KP_9000_9XHML_X_V3_1 // #define MACHINE_KP_9000_9XHML_X_V3_1
@@ -18,6 +28,7 @@
// #define MACHINE_HG0402XG_V1_1 // #define MACHINE_HG0402XG_V1_1
// #define MACHINE_SWTG018AS_A_V_2_0 // #define MACHINE_SWTG018AS_A_V_2_0
// #define MACHINE_SWTGW218AS // #define MACHINE_SWTGW218AS
// #define MACHINE_PCB_SWTG018AS_V2_1_0
// #define MACHINE_PCB_K0402WS_V3 // #define MACHINE_PCB_K0402WS_V3
// #define MACHINE_K0501W_V2_0 // #define MACHINE_K0501W_V2_0
// #define MACHINE_LIANGUO_ZX_SWTGW215AS // #define MACHINE_LIANGUO_ZX_SWTGW215AS
@@ -94,6 +105,6 @@ typedef struct machine_runtime
uint8_t isN : 1; uint8_t isN : 1;
}; };
void machine_custom_init(void); void machine_custom_init(void) __banked;
#endif #endif
+122
View File
@@ -0,0 +1,122 @@
/*
* Per-machine one-shot boot hooks, hosted in BANK2 so board-specific
* tables and code do not consume the common bank.
*/
#include <stdint.h>
#include "machine.h"
#include "rtl837x_pins.h"
#include "rtl837x_leds.h"
#include "rtl837x_sfr.h"
#include "rtl837x_regs.h"
#include "rtl837x_common.h"
#pragma codeseg BANK2
#pragma constseg BANK2
#if defined(MACHINE_KP_9000_6XH_X2) || \
defined(MACHINE_KP_9000_6XH_X2_V2_1) || \
defined(MACHINE_KP_9000_6XHML_X2_V2_1)
void machine_custom_init(void) __banked
{
reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6);
}
#elif defined MACHINE_PCB_SWTG018AS_V2_1_0
// Stock-firmware values for what the LED-set encoding cannot express: the
// bi-color SFP LED (blue pin at 10G) and the PIN_MUX_0 routing of that pin
// to the LED controller. Runs after leds_setup(), which covers the rest.
static __code const struct { uint16_t reg; uint32_t val; } custom_init_regs[] = {
{ RTL837X_REG_LED3_0_SET1, 0x00100000UL },
{ RTL837X_REG_LED1_0_SET1, 0x01400155UL },
{ RTL837X_REG_LED1_0_SET0, 0x01740141UL },
{ RTL837X_REG_LED_GLB_IO_EN, 0x7f24977fUL },
{ RTL837X_PIN_MUX_0, 0x20db6880UL },
};
void machine_custom_init(void) __banked
{
uint8_t i;
// REG_SET is a multi-statement macro without a do-while wrapper: braces required
for (i = 0; i < sizeof(custom_init_regs) / sizeof(custom_init_regs[0]); i++) {
REG_SET(custom_init_regs[i].reg, custom_init_regs[i].val);
}
}
#elif defined(MACHINE_PCB_K0402WS_V3) || defined(MACHINE_HI_K0402WS)
void machine_custom_init(void) __banked
{
reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6);
}
#elif defined MACHINE_FNS1200P
void machine_custom_init(void) __banked
{
reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6);
}
#elif defined MACHINE_PCB_SWTG024AS_A_2_0_1
void machine_custom_init(void) __banked
{
reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6);
reg_bit_set(RTL837X_REG_LED_MODE, 17);
reg_bit_clear(RTL837X_REG_LED_MODE, 9);
reg_bit_clear(RTL837X_REG_LED_MODE, 7);
}
#elif defined MACHINE_SWTG024AS_A_2_0_1_5C_1SFP
void machine_custom_init(void) __banked
{
uint16_t pval;
reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6);
reg_bit_set(RTL837X_REG_LED_MODE, 17);
reg_bit_clear(RTL837X_REG_LED_MODE, 9);
reg_bit_clear(RTL837X_REG_LED_MODE, 7);
// OEM firmware sets these companion SDS0 polarity bits for the RTL8221B.
sds_read(0, 0, 0);
pval = SFR_DATA_U16;
sds_write_v(0, 0, 0, pval | 0x100);
sds_read(0, 6, 2);
pval = SFR_DATA_U16;
sds_write_v(0, 6, 2, pval | 0x4000);
}
#elif defined MACHINE_SWTG024AS_V2_0
void machine_custom_init(void) __banked
{
uint16_t pval;
reg_bit_set(RTL837X_REG_LED_GLB_IO_EN, 6);
reg_bit_set(RTL837X_REG_LED_MODE, 17);
reg_bit_clear(RTL837X_REG_LED_MODE, 9);
reg_bit_clear(RTL837X_REG_LED_MODE, 7);
// OEM firmware sets these companion SDS0 polarity bits for the RTL8221B.
sds_read(0, 0, 0);
pval = SFR_DATA_U16;
sds_write_v(0, 0, 0, pval | 0x100);
sds_read(0, 6, 2);
pval = SFR_DATA_U16;
sds_write_v(0, 6, 2, pval | 0x4000);
}
#elif defined MACHINE_ZX310S_4T2XT
void machine_custom_init(void) __banked
{
// For this device, the reset value of RTL837X_PIN_MUX_0 is 0x30000000,
// which would disables all LEDS, enable them manually:
REG_SET(RTL837X_PIN_MUX_0, 0x30db68bf);
}
#elif defined MACHINE_FG_4GT_2SX_V2_0
void machine_custom_init(void) __banked
{
REG_SET(RTL837X_REG_LED_GLB_IO_EN, 0x7624155b);
}
#else
void machine_custom_init(void) __banked { }
#endif
+15 -9
View File
@@ -8,6 +8,7 @@
#define SYS_TICK_HZ 200 #define SYS_TICK_HZ 200
#define CPU_PORT 9 #define CPU_PORT 9
#define NUL '\0'
// Define Port-masks for 9-port devices and 6-port devices // Define Port-masks for 9-port devices and 6-port devices
#define PMASK_9 0x1ff #define PMASK_9 0x1ff
@@ -125,6 +126,7 @@ extern __xdata struct uip_eth_addr uip_ethaddr;
// Headers for calls in the common code area (HOME/BANK0) // Headers for calls in the common code area (HOME/BANK0)
void print_string_no_syslog(__code char *p); void print_string_no_syslog(__code char *p);
void print_string_newline_no_syslog(__code char *p);
void print_string(__code char *p); void print_string(__code char *p);
void print_string_x(__xdata char *p); void print_string_x(__xdata char *p);
void print_long(uint32_t a); void print_long(uint32_t a);
@@ -134,6 +136,7 @@ void itoa(uint8_t v);
void print_sfr_data(void); void print_sfr_data(void);
void print_phy_data(void); void print_phy_data(void);
void print_cmd_prompt(void); void print_cmd_prompt(void);
void print_phys_port(uint8_t port);
void phy_write_mask(uint16_t phy_mask, uint8_t dev_id, uint16_t reg, uint16_t v); void phy_write_mask(uint16_t phy_mask, uint8_t dev_id, uint16_t reg, uint16_t v);
void phy_write(uint8_t phy_id, uint8_t dev_id, uint16_t reg, uint16_t v); void phy_write(uint8_t phy_id, uint8_t dev_id, uint16_t reg, uint16_t v);
void phy_read(uint8_t phy_id, uint8_t dev_id, uint16_t reg); void phy_read(uint8_t phy_id, uint8_t dev_id, uint16_t reg);
@@ -149,7 +152,8 @@ void sleep(uint16_t t);
void write_char_no_syslog(char c); void write_char_no_syslog(char c);
void write_char(char c); void write_char(char c);
void print_reg(uint16_t reg); void print_reg(uint16_t reg);
uint8_t sfp_read_reg(uint8_t slot, uint8_t reg); bool sfp_read_block(uint8_t slot, uint8_t reg, uint8_t len) __banked __reentrant;
extern __xdata uint8_t sfp_buf[16];
void reg_bit_set(uint16_t reg_addr, char bit); void reg_bit_set(uint16_t reg_addr, char bit);
void reg_bit_clear(uint16_t reg_addr, char bit); void reg_bit_clear(uint16_t reg_addr, char bit);
uint8_t reg_bit_test(uint16_t reg_addr, char bit); uint8_t reg_bit_test(uint16_t reg_addr, char bit);
@@ -157,18 +161,20 @@ void sfr_mask_data(uint8_t n, uint8_t mask, uint8_t set);
void sfr_set_zero(void); void sfr_set_zero(void);
void reset_chip(void); void reset_chip(void);
void memcpy(__xdata void * __xdata dst, __xdata const void * __xdata src, uint16_t len); void memcpy(__xdata void * __xdata dst, __xdata const void * __xdata src, uint16_t len);
void memcpyc(register __xdata uint8_t *dst, register __code uint8_t *src, register uint16_t len); void memcpyc(__xdata uint8_t *dst, __code uint8_t *src, uint16_t len);
void memset(register __xdata uint8_t *dst, register __xdata uint8_t v, register uint8_t len); void memset(__xdata uint8_t *dst, __xdata uint8_t v, uint8_t len);
uint16_t strlen(register __code const char *s); uint16_t strlen(__code const char *s);
uint16_t strlen_x(register __xdata const char *s); uint16_t strlen_x(__xdata const char *s);
uint16_t strtox(register __xdata uint8_t *dst, register __code const char *s); uint16_t strtox(__xdata uint8_t *dst, __code const char *s);
uint16_t strcpy(register __xdata uint8_t *dst, register const char *s); uint16_t strcpy(__xdata uint8_t *dst, const char *s);
char strcmp(register __xdata const uint8_t *a, register __code const uint8_t *b); char strcmp(__xdata const uint8_t *a, __code const uint8_t *b);
bool strstart(__xdata const uint8_t *a, __code const uint8_t *b);
bool strstart_x(__xdata const uint8_t *a, __xdata const uint8_t *b);
void tcpip_output(void); void tcpip_output(void);
uint8_t read_flash(uint8_t bank, __code uint8_t *addr); uint8_t read_flash(uint8_t bank, __code uint8_t *addr);
void get_random_32(void); void get_random_32(void);
void read_reg_timer(__xdata uint32_t * tmr); void read_reg_timer(__xdata uint32_t * tmr);
void sfp_print_info(uint8_t sfp); bool sfp_print_info(uint8_t sfp);
bool gpio_pin_test(uint8_t pin); bool gpio_pin_test(uint8_t pin);
void set_sys_led_state(uint8_t state); void set_sys_led_state(uint8_t state);
void sds_read(uint8_t sds_id, uint8_t page, uint8_t reg); void sds_read(uint8_t sds_id, uint8_t page, uint8_t reg);
+2 -2
View File
@@ -262,7 +262,7 @@ void phy_set_speed(void) __banked
{ {
uint16_t v; uint16_t v;
print_string("Setting port "); write_char(machine.log_to_phys_port[phy_settings.port] + '0'); print_string("Setting port "); print_phys_port(phy_settings.port);
if (machine.n_10g && phy_settings.port == 3) if (machine.n_10g && phy_settings.port == 3)
phy_settings.is10g_port = 1; phy_settings.is10g_port = 1;
if (machine.n_10g == 2 && phy_settings.port == 8) if (machine.n_10g == 2 && phy_settings.port == 8)
@@ -381,7 +381,7 @@ void phy_set_duplex(void) __banked
{ {
uint16_t v; uint16_t v;
print_string("Setting port "); write_char(machine.log_to_phys_port[phy_settings.port] + '0'); print_string("Setting port "); print_phys_port(phy_settings.port);
if (phy_settings.duplex) if (phy_settings.duplex)
print_string(" to full duplex"); print_string(" to full duplex");
else else
+58
View File
@@ -1,6 +1,11 @@
#include "rtl837x_pins.h" #include "rtl837x_pins.h"
#include "rtl837x_common.h" #include "rtl837x_common.h"
#include "rtl837x_sfr.h"
#include "rtl837x_regs.h" #include "rtl837x_regs.h"
#include "machine.h"
extern __code const struct machine machine;
extern __xdata uint8_t sfr_data[4];
#pragma codeseg BANK2 #pragma codeseg BANK2
#pragma constseg BANK2 #pragma constseg BANK2
@@ -121,3 +126,56 @@ void gpio_output_setup(uint8_t pin, __xdata uint8_t initial_val) __banked{
reg_bit_set(gpio_direction_reg(pin), (pin % 32)); reg_bit_set(gpio_direction_reg(pin), (pin % 32));
} }
/*
* Read up to 16 consecutive registers of the EEPROM via I2C into sfp_buf
*/
bool sfp_read_block(uint8_t slot, uint8_t reg, uint8_t len) __banked __reentrant
{
uint8_t dev;
uint8_t val;
len--;
if (len > 15)
return false;
dev = (reg & 0x80) ? 0x51 : 0x50; // 0x51 holds the diagnostics, 0x50 the module data
reg &= 0x7f;
REG_WRITE(RTL837X_REG_I2C_IN, 0, 0, 0, reg);
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00,
0x1 << (I2C_MEM_ADDR_WIDTH - 16) | len,
(dev >> 5) | i2c_bus_from_scl_pin(machine.sfp_port[slot].i2c.scl) << 5
| i2c_bus_from_sda_pin(machine.sfp_port[slot].i2c.sda) << 2,
((dev << 3) & 0xff) | 0x1);
do {
reg_read(RTL837X_REG_I2C_CTRL);
} while (SFR_DATA_0 & 0x1);
if (SFR_DATA_0 & 0x2)
return false;
for (uint8_t i = 0; i <= len; i++) {
switch (i & 0x3) {
case 0:
reg_read(RTL837X_REG_I2C_OUT + i);
val = SFR_DATA_0;
break;
case 1:
val = SFR_DATA_8;
break;
case 2:
val = SFR_DATA_16;
break;
default:
val = SFR_DATA_24;
break;
}
sfp_buf[i] = val;
}
return true;
}
+8 -21
View File
@@ -30,7 +30,7 @@ __xdata uint32_t l2_head;
__xdata struct vlan_settings vlan_settings; __xdata struct vlan_settings vlan_settings;
void port_mirror_set(register uint8_t port, __xdata uint16_t rx_pmask, __xdata uint16_t tx_pmask) __banked void port_mirror_set(uint8_t port, __xdata uint16_t rx_pmask, __xdata uint16_t tx_pmask) __banked
{ {
print_string("\nport_mirror_set called \n"); print_string("\nport_mirror_set called \n");
print_string("Mirroring port: "); print_byte(port); print_string(" with rx-mask: "); print_string("Mirroring port: "); print_byte(port); print_string(" with rx-mask: ");
@@ -162,7 +162,7 @@ void vlan_name_remove(uint16_t vlan) __banked
* Reads VLAN information from VLAN table * Reads VLAN information from VLAN table
* Returns data in sfr_data * Returns data in sfr_data
*/ */
int8_t vlan_get(register uint16_t vlan) __banked int8_t vlan_get(uint16_t vlan) __banked
{ {
if (vlan >= 0xfff) // VLAN 4095 is special if (vlan >= 0xfff) // VLAN 4095 is special
return -1; return -1;
@@ -177,7 +177,7 @@ int8_t vlan_get(register uint16_t vlan) __banked
} }
__xdata uint16_t vlan_name(register uint16_t vlan) __banked __xdata uint16_t vlan_name(uint16_t vlan) __banked
{ {
__xdata int16_t i = 0; __xdata int16_t i = 0;
__xdata uint8_t begin = 1; __xdata uint8_t begin = 1;
@@ -390,10 +390,7 @@ void port_l2_learned(void) __banked
print_string("\tlearned\t"); print_string("\tlearned\t");
port |= (sfr_data[3] & 0x3) << 2; port |= (sfr_data[3] & 0x3) << 2;
if (port < 9) print_phys_port(port);
write_char(machine.log_to_phys_port[port] + '0');
else
print_string("CPU");
} }
entry++; entry++;
@@ -431,7 +428,7 @@ void port_stats_print(void) __banked
{ {
print_string("\nPort\tState\tLink\tTxGood\t\tTxBad\t\tRxGood\t\tRxBad\n"); print_string("\nPort\tState\tLink\tTxGood\t\tTxBad\t\tRxGood\t\tRxBad\n");
for (uint8_t i = machine.min_port; i <= machine.max_port; i++) { for (uint8_t i = machine.min_port; i <= machine.max_port; i++) {
write_char('0' + machine.log_to_phys_port[i]); write_char('\t'); print_phys_port(i); write_char('\t');
if (!machine.is_sfp[i]) { if (!machine.is_sfp[i]) {
phy_read(i, PHY_MMD31, 0xa610); phy_read(i, PHY_MMD31, 0xa610);
@@ -508,14 +505,14 @@ void port_stats_print(void) __banked
} }
void port_isolate(register uint8_t port, __xdata uint16_t pmask) __banked void port_isolate(uint8_t port, __xdata uint16_t pmask) __banked
{ {
if (port <= machine.max_port) if (port <= machine.max_port)
REG_SET(RTL837X_PORT_ISOLATION_BASE + (port << 2), pmask); REG_SET(RTL837X_PORT_ISOLATION_BASE + (port << 2), pmask);
} }
uint16_t port_isolation_get(register uint8_t port) __banked uint16_t port_isolation_get(uint8_t port) __banked
{ {
if (port > machine.max_port) if (port > machine.max_port)
return 0; return 0;
@@ -606,7 +603,7 @@ void port_eee_disable(uint8_t port) __banked
void port_eee_status(uint8_t port) __banked void port_eee_status(uint8_t port) __banked
{ {
print_string("Port: "); write_char('0' + machine.log_to_phys_port[port]); print_string("Port: "); print_phys_port(port);
print_string(": "); print_string(": ");
if (machine.is_sfp[port]) { if (machine.is_sfp[port]) {
print_string("SFP\n"); print_string("SFP\n");
@@ -801,16 +798,6 @@ void print_port_ingress_filter_mode(vlan_ingress_mode_t mode) __banked
} }
} }
static void print_phys_port(uint8_t port) __banked
{
if (port >= machine.min_port && port <= machine.max_port)
write_char(machine.log_to_phys_port[port] + '0');
else if (port == 9)
write_char('9');
else
write_char('?');
}
void print_vlan_ingress_port(uint8_t log_port) __banked void print_vlan_ingress_port(uint8_t log_port) __banked
{ {
print_phys_port(log_port);write_char('\t'); print_phys_port(log_port);write_char('\t');
+5 -5
View File
@@ -48,8 +48,8 @@ extern __xdata struct vlan_settings vlan_settings;
uint8_t port_l2_forget(void) __banked; uint8_t port_l2_forget(void) __banked;
void port_l2_learned(void) __banked; void port_l2_learned(void) __banked;
void port_stats_print(void) __banked; void port_stats_print(void) __banked;
int8_t vlan_get(register uint16_t vlan) __banked; int8_t vlan_get(uint16_t vlan) __banked;
__xdata uint16_t vlan_name(register uint16_t vlan) __banked; __xdata uint16_t vlan_name(uint16_t vlan) __banked;
void vlan_name_remove(uint16_t vlan) __banked; void vlan_name_remove(uint16_t vlan) __banked;
void vlan_setup(void) __banked; void vlan_setup(void) __banked;
void port_pvid_set(uint8_t port, __xdata uint16_t pvid) __banked; void port_pvid_set(uint8_t port, __xdata uint16_t pvid) __banked;
@@ -57,7 +57,7 @@ uint16_t port_pvid_get(uint8_t port) __banked;
void vlan_create(void) __banked; void vlan_create(void) __banked;
void vlan_delete(uint16_t vlan) __banked; void vlan_delete(uint16_t vlan) __banked;
void vlan_dump(void) __banked; void vlan_dump(void) __banked;
void port_mirror_set(register uint8_t port, __xdata uint16_t rx_pmask, __xdata uint16_t tx_pmask) __banked; void port_mirror_set(uint8_t port, __xdata uint16_t rx_pmask, __xdata uint16_t tx_pmask) __banked;
void port_mirror_del(void) __banked; void port_mirror_del(void) __banked;
bool port_ingress_filter(__xdata uint8_t port, __xdata vlan_ingress_mode_t type) __banked; bool port_ingress_filter(__xdata uint8_t port, __xdata vlan_ingress_mode_t type) __banked;
void port_l2_setup(void) __banked; void port_l2_setup(void) __banked;
@@ -73,7 +73,7 @@ void port_eee_status(uint8_t port) __banked;
void print_port_ingress_filter_mode(vlan_ingress_mode_t mode) __banked; void print_port_ingress_filter_mode(vlan_ingress_mode_t mode) __banked;
bool port_ingress_vlan_filter_set(__xdata uint8_t port, __xdata bool enabled) __banked; bool port_ingress_vlan_filter_set(__xdata uint8_t port, __xdata bool enabled) __banked;
bool port_ingress_vlan_filter_get(__xdata uint8_t port) __banked; bool port_ingress_vlan_filter_get(__xdata uint8_t port) __banked;
void port_isolate(register uint8_t port, __xdata uint16_t pmask) __banked; void port_isolate(uint8_t port, __xdata uint16_t pmask) __banked;
uint16_t port_isolation_get(register uint8_t port) __banked; uint16_t port_isolation_get(uint8_t port) __banked;
#endif #endif
+5
View File
@@ -14,6 +14,11 @@
#include "uip.h" #include "uip.h"
#include "machine.h" #include "machine.h"
// All entry points are __banked and nothing here runs from an interrupt,
// so the module does not need to stay in the resident bank
#pragma codeseg BANK2
#pragma constseg BANK2
extern __code struct machine machine; extern __code struct machine machine;
extern __xdata uint8_t sfr_data[4]; extern __xdata uint8_t sfr_data[4];
+114 -66
View File
@@ -140,6 +140,7 @@ __xdata char sfp_module_vendor[2][17];
__xdata char sfp_module_model[2][17]; __xdata char sfp_module_model[2][17];
__xdata char sfp_module_serial[2][17]; __xdata char sfp_module_serial[2][17];
__xdata uint8_t sfp_options[2]; __xdata uint8_t sfp_options[2];
__xdata uint8_t sfp_buf[16]; /* scratch for one I2C transaction, the controller reads at most 16 bytes */
__xdata uint8_t sfp_speed[2]; __xdata uint8_t sfp_speed[2];
__xdata uint8_t sfp_quirks[2]; __xdata uint8_t sfp_quirks[2];
__xdata bool button_last; __xdata bool button_last;
@@ -289,6 +290,12 @@ void print_string_no_syslog(__code char *p)
write_char_no_syslog(*p++); write_char_no_syslog(*p++);
} }
void print_string_newline_no_syslog(__code char *p)
{
write_char_no_syslog('\n');
print_string_no_syslog(p);
}
void print_string_x(__xdata char *p) void print_string_x(__xdata char *p)
{ {
while (*p) while (*p)
@@ -304,20 +311,20 @@ void memcpy(__xdata void * __xdata dst, __xdata const void * __xdata src, uint16
*d++ = *s++; *d++ = *s++;
} }
void memcpyc(register __xdata uint8_t *dst, register __code uint8_t *src, register uint16_t len) void memcpyc(__xdata uint8_t *dst, __code uint8_t *src, uint16_t len)
{ {
while (len--) while (len--)
*dst++ = *src++; *dst++ = *src++;
} }
void memset(register __xdata uint8_t *dst, register __xdata uint8_t v, register uint8_t len) void memset(__xdata uint8_t *dst, __xdata uint8_t v, uint8_t len)
{ {
while (len--) while (len--)
*dst++ = v; *dst++ = v;
} }
uint16_t strtox(register __xdata uint8_t *dst, register __code const char *s) uint16_t strtox(__xdata uint8_t *dst, __code const char *s)
{ {
__xdata uint8_t *b = dst; __xdata uint8_t *b = dst;
while (*s) while (*s)
@@ -327,7 +334,7 @@ uint16_t strtox(register __xdata uint8_t *dst, register __code const char *s)
} }
uint16_t strlen(register __code const char *s) uint16_t strlen(__code const char *s)
{ {
uint16_t l = 0; uint16_t l = 0;
while (s[l]) while (s[l])
@@ -336,7 +343,7 @@ uint16_t strlen(register __code const char *s)
} }
uint16_t strlen_x(register __xdata const char *s) uint16_t strlen_x(__xdata const char *s)
{ {
uint16_t l = 0; uint16_t l = 0;
while (s[l]) while (s[l])
@@ -345,7 +352,7 @@ uint16_t strlen_x(register __xdata const char *s)
} }
char strcmp(register __xdata const uint8_t *a, register __code const uint8_t *b) char strcmp(__xdata const uint8_t *a, __code const uint8_t *b)
{ {
uint8_t i = 0; uint8_t i = 0;
@@ -360,6 +367,32 @@ char strcmp(register __xdata const uint8_t *a, register __code const uint8_t *b)
} }
/*
* True when b is a prefix of a. Unlike strcmp() the byte after the match is not
* compared, and unlike is_word_x() it need not be a separator.
*/
bool strstart(__xdata const uint8_t *a, __code const uint8_t *b)
{
uint8_t i = 0;
while (b[i] && (b[i] == a[i]))
i++;
return !b[i];
}
bool strstart_x(__xdata const uint8_t *a, __xdata const uint8_t *b)
{
uint8_t i = 0;
while (b[i] && (b[i] == a[i]))
i++;
return !b[i];
}
void print_short(uint16_t a) void print_short(uint16_t a)
{ {
// allocating the registers first improves the sdcc code here // allocating the registers first improves the sdcc code here
@@ -634,7 +667,7 @@ void nic_rx_header(uint16_t ring_ptr)
* data will be returned in the xmem buffer points to * data will be returned in the xmem buffer points to
* ring_ptr is the current position of the RX Ring on the ASIC side * ring_ptr is the current position of the RX Ring on the ASIC side
*/ */
void nic_rx_packet(register uint16_t buffer, register uint16_t ring_ptr) void nic_rx_packet(uint16_t buffer, uint16_t ring_ptr)
{ {
SFR_NIC_DATA_U16LE = buffer; SFR_NIC_DATA_U16LE = buffer;
SFR_NIC_RING_U16LE = ring_ptr; SFR_NIC_RING_U16LE = ring_ptr;
@@ -780,6 +813,19 @@ void print_reg(uint16_t reg)
print_sfr_data(); print_sfr_data();
} }
// Print the physical port of a logical port number.
void print_phys_port(uint8_t port)
{
if (port < CPU_PORT)
write_char(machine.log_to_phys_port[port] + '0');
else if (port == CPU_PORT)
print_string("CPU");
else {
print_string("UNKNOWN ");
write_char(port + '0');
}
}
/* /*
// TODO: This uses 2 DSEG bytes and is not used! // TODO: This uses 2 DSEG bytes and is not used!
@@ -1036,37 +1082,6 @@ void sds_config(uint8_t sds, uint8_t mode)
} }
/*
* Read a register of the EEPROM via I2C
*/
uint8_t sfp_read_reg(uint8_t slot, uint8_t reg)
{
if (reg & 0x80) { // Configure SFP readings address (0x51) as I2C device address
reg &= 0x7f;
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | 0, 0x51 >> 5, (0x51 << 3) & 0xff);
} else {
REG_WRITE(RTL837X_REG_I2C_CTRL, 0x00, 0x1 << (I2C_MEM_ADDR_WIDTH-16) | 0, 0x50 >> 5, (0x50 << 3) & 0xff);
}
reg_read_m(RTL837X_REG_I2C_CTRL);
sfr_mask_data(1, 0xfc, i2c_bus_from_scl_pin(machine.sfp_port[slot].i2c.scl) << 5 | i2c_bus_from_sda_pin(machine.sfp_port[slot].i2c.sda) << 2);
reg_write_m(RTL837X_REG_I2C_CTRL);
REG_WRITE(RTL837X_REG_I2C_IN, 0, 0, 0, reg);
// Execute I2C Read
reg_bit_set(RTL837X_REG_I2C_CTRL, 0);
// Wait for execution to finish
do {
reg_read_m(RTL837X_REG_I2C_CTRL);
} while (sfr_data[3] & 0x1);
reg_read_m(RTL837X_REG_I2C_OUT);
return sfr_data[3];
}
/* /*
* Adds TX Header to uip_buf and calls nic_tx_packet to send the packet * Adds TX Header to uip_buf and calls nic_tx_packet to send the packet
* over the wire * over the wire
@@ -1205,7 +1220,7 @@ void handle_tx(void)
} }
static inline uint8_t sfp_rate_to_sds_config(register uint8_t rate) static inline uint8_t sfp_rate_to_sds_config(uint8_t rate)
{ {
if (rate == 0x1 || rate == 0x2) if (rate == 0x1 || rate == 0x2)
return SDS_100FX; return SDS_100FX;
@@ -1219,36 +1234,46 @@ static inline uint8_t sfp_rate_to_sds_config(register uint8_t rate)
} }
void sfp_print_info(uint8_t sfp) bool sfp_print_info(uint8_t sfp)
{ {
// This loops over the Vendor-name, Vendor OUI, Vendor PN and Vendor rev ASCII fields // This loops over the Vendor-name, Vendor OUI, Vendor PN and Vendor rev ASCII fields
for (uint8_t i = 20; i < 60; i++) { for (uint8_t i = 16; i < 64; i++) {
if (i >= 36 && i < 40) // Skip Non-ASCII codes if (!(i & 0xf) && !sfp_read_block(sfp, i, 16))
return false;
if (i < 20 || i >= 60 || (i >= 36 && i < 40)) // Skip Non-ASCII codes
continue; continue;
uint8_t c = sfp_read_reg(sfp, i); uint8_t c = sfp_buf[i & 0xf];
if (c) if (c)
write_char(c); write_char(c);
} }
print_string("\n"); print_string("\n");
return true;
} }
// Normalize strings from EEPROM by removing any trailing spaces; this allows simpler comparisons // Normalize strings from EEPROM by removing any trailing spaces; this allows simpler comparisons
void sfp_read_field(__xdata char *dst, uint8_t sfp, uint8_t start, uint8_t length) __reentrant bool sfp_read_field(__xdata char *dst, uint8_t sfp, uint8_t start, uint8_t length) __reentrant
{ {
dst[length] = '\0'; if (!sfp_read_block(sfp, start, length))
return false;
for (uint8_t i = 0; i < length; i++) dst[length] = NUL;
dst[i] = sfp_read_reg(sfp, start + i); memcpy(dst, sfp_buf, length);
while (length > 0 && dst[--length] == ' ') while (length > 0 && dst[--length] == ' ')
dst[length] = '\0'; dst[length] = NUL;
return true;
} }
void sfp_get_info(uint8_t sfp) bool sfp_get_info(uint8_t sfp)
{ {
sfp_read_field(sfp_module_vendor[sfp], sfp, 20, 16); if (!sfp_read_field(sfp_module_vendor[sfp], sfp, 20, 16))
sfp_read_field(sfp_module_model[sfp], sfp, 40, 16); return false;
sfp_read_field(sfp_module_serial[sfp], sfp, 68, 16); if (!sfp_read_field(sfp_module_model[sfp], sfp, 40, 16))
return false;
return sfp_read_field(sfp_module_serial[sfp], sfp, 68, 16);
} }
void sfp_apply_quirks(uint8_t sfp) __reentrant void sfp_apply_quirks(uint8_t sfp) __reentrant
@@ -1267,7 +1292,7 @@ void sfp_apply_quirks(uint8_t sfp) __reentrant
if (!(sfp_options[sfp] & 0x40)) { if (!(sfp_options[sfp] & 0x40)) {
// The module reports that DDM is not implemented, but try a dummy read to confirm // The module reports that DDM is not implemented, but try a dummy read to confirm
// 0xff would mean a failed I2C read or an impossible (per spec) voltage greater than 6.5V // 0xff would mean a failed I2C read or an impossible (per spec) voltage greater than 6.5V
if (sfp_read_reg(sfp, 226) != 0xff) { if (sfp_read_block(sfp, 226, 1) && sfp_buf[0] != 0xff) {
sfp_options[sfp] |= 0x40; sfp_options[sfp] |= 0x40;
} }
} }
@@ -1291,17 +1316,17 @@ void setup_sfp_gpio(void)
} }
} }
void handle_sfp(void) static bool sfp_module_read(uint8_t sfp)
{ {
for (uint8_t sfp = 0; sfp < machine.n_sfp; sfp++) { uint8_t rate;
if (!gpio_pin_test(machine.sfp_port[sfp].pin_detect)) {
if (sfp_pins_last & (0x1 << (sfp << 2))) {
sfp_pins_last &= ~(0x01 << (sfp << 2));
print_string("\n<MODULE INSERTED> Slot: "); write_char('1' + sfp);
// Read Reg 11: Encoding, see SFF-8472 and SFF-8024 // Read Reg 11: Encoding, see SFF-8472 and SFF-8024
// Read Reg 12: Signalling rate (including overhead) in 100Mbit: 0xd: 1Gbit, 0x67:10Gbit // Read Reg 12: Signalling rate (including overhead) in 100Mbit: 0xd: 1Gbit, 0x67:10Gbit
delay(100); // Delay, because some modules need time to wake up delay(100); // Delay, because some modules need time to wake up
uint8_t rate = sfp_read_reg(sfp, 12); if (!sfp_read_block(sfp, 11, 2))
return false;
rate = sfp_buf[1];
if (sfp_speed[sfp] == SFP_SPEED_100M) if (sfp_speed[sfp] == SFP_SPEED_100M)
rate = 0x1; rate = 0x1;
else if (sfp_speed[sfp] == SFP_SPEED_1G) else if (sfp_speed[sfp] == SFP_SPEED_1G)
@@ -1311,13 +1336,36 @@ void handle_sfp(void)
else if (sfp_speed[sfp] == SFP_SPEED_10G) else if (sfp_speed[sfp] == SFP_SPEED_10G)
rate = 0x69; rate = 0x69;
print_string(" Rate: "); print_byte(rate); // Normally 1, but 0 for DAC, can be ignored? print_string(" Rate: "); print_byte(rate); // Normally 1, but 0 for DAC, can be ignored?
print_string(" Encoding: "); print_byte(sfp_read_reg(sfp, 11)); print_string(" Encoding: "); print_byte(sfp_buf[0]);
print_string(" Module: "); sfp_print_info(sfp); print_string(" Module: ");
if (!sfp_print_info(sfp))
return false;
print_string("\n"); print_string("\n");
sfp_options[sfp] = sfp_read_reg(sfp, 92);
sfp_get_info(sfp); if (!sfp_read_block(sfp, 92, 1))
return false;
sfp_options[sfp] = sfp_buf[0];
if (!sfp_get_info(sfp))
return false;
sfp_apply_quirks(sfp); sfp_apply_quirks(sfp);
sds_config(machine.sfp_port[sfp].sds, sfp_rate_to_sds_config(rate)); sds_config(machine.sfp_port[sfp].sds, sfp_rate_to_sds_config(rate));
return true;
}
void handle_sfp(void)
{
for (uint8_t sfp = 0; sfp < machine.n_sfp; sfp++) {
if (!gpio_pin_test(machine.sfp_port[sfp].pin_detect)) {
if (sfp_pins_last & (0x1 << (sfp << 2))) {
sfp_pins_last &= ~(0x01 << (sfp << 2));
print_string("\n<MODULE INSERTED> Slot: "); write_char('1' + sfp);
if (!sfp_module_read(sfp)) {
print_string("SFP: an I2C read failed, retrying on the next poll\n");
sfp_pins_last |= 0x01 << (sfp << 2);
}
} }
} else { } else {
if (!(sfp_pins_last & (0x1 << (sfp << 2)))) { if (!(sfp_pins_last & (0x1 << (sfp << 2)))) {
@@ -2021,7 +2069,7 @@ void check_and_flash_update_image(void)
* because itohex() is inline and brings its own frame. */ * because itohex() is inline and brings its own frame. */
void set_hostname_default(void) void set_hostname_default(void)
{ {
if (hostname[0] != '\0') if (hostname[0] != NUL)
return; return;
strcpy((__xdata uint8_t *)hostname, "RTLPlayground-"); strcpy((__xdata uint8_t *)hostname, "RTLPlayground-");
@@ -2031,7 +2079,7 @@ void set_hostname_default(void)
hostname[17] = hex[uip_ethaddr.addr[4] & 0xf]; hostname[17] = hex[uip_ethaddr.addr[4] & 0xf];
hostname[18] = hex[uip_ethaddr.addr[5] >> 4]; hostname[18] = hex[uip_ethaddr.addr[5] >> 4];
hostname[19] = hex[uip_ethaddr.addr[5] & 0xf]; hostname[19] = hex[uip_ethaddr.addr[5] & 0xf];
hostname[20] = '\0'; hostname[20] = NUL;
} }
+8 -8
View File
@@ -30,16 +30,16 @@ void syslog_start(void) __banked
uip_ipaddr(server_ip, state.server_ip[0], state.server_ip[1], state.server_ip[2], state.server_ip[3]); uip_ipaddr(server_ip, state.server_ip[0], state.server_ip[1], state.server_ip[2], state.server_ip[3]);
state.syslog_conn = uip_udp_new(&server_ip, HTONS(514)); state.syslog_conn = uip_udp_new(&server_ip, HTONS(514));
if (state.syslog_conn == 0) { if (state.syslog_conn == 0) {
print_string_no_syslog("Failed to create a new UDP client\n"); print_string_newline_no_syslog("Failed to create a new UDP client");
return; return;
} }
print_string_no_syslog("Started syslog to IP "); print_string_newline_no_syslog("Started syslog to IP ");
itoa(state.server_ip[0]); write_char('.'); itoa(state.server_ip[1]); write_char('.'); itoa(state.server_ip[0]); write_char('.'); itoa(state.server_ip[1]); write_char('.');
itoa(state.server_ip[2]); write_char('.'); itoa(state.server_ip[3]); write_char('\n'); itoa(state.server_ip[2]); write_char('.'); itoa(state.server_ip[3]); write_char('\n');
state.enabled = 1; state.enabled = 1;
} }
else { else {
print_string_no_syslog("Syslog is already running\n"); print_string_newline_no_syslog("Syslog is already running");
} }
} }
@@ -49,9 +49,9 @@ void syslog_stop(void) __banked
if (state.syslog_conn != 0) { if (state.syslog_conn != 0) {
uip_udp_remove(state.syslog_conn); uip_udp_remove(state.syslog_conn);
state.syslog_conn = 0; state.syslog_conn = 0;
print_string_no_syslog("Stopped syslog\n"); print_string_newline_no_syslog("Stopped syslog");
} else { } else {
print_string_no_syslog("Syslog is not running\n"); print_string_newline_no_syslog("Syslog is not running");
} }
} }
@@ -62,19 +62,19 @@ void syslog_callback(uint16_t lport) __banked
if ((state.readptr != state.writeptr) && state.line_available) if ((state.readptr != state.writeptr) && state.line_available)
{ {
int16_t log_size = state.writeptr - state.readptr; __xdata int16_t log_size = state.writeptr - state.readptr;
if (log_size < 0) if (log_size < 0)
log_size += LOGBUF_SIZE; log_size += LOGBUF_SIZE;
// Skipping linefeeds at the start of the log line // Skipping linefeeds at the start of the log line
uint16_t log_start = state.readptr; __xdata uint16_t log_start = state.readptr;
while (log_size > 0 && logbuf[log_start] == '\n') { while (log_size > 0 && logbuf[log_start] == '\n') {
log_start = (log_start + 1) & (LOGBUF_SIZE - 1); log_start = (log_start + 1) & (LOGBUF_SIZE - 1);
log_size--; log_size--;
} }
// Skipping linefeeds and whitespaces at the end of the log line // Skipping linefeeds and whitespaces at the end of the log line
uint16_t log_end = state.writeptr; __xdata uint16_t log_end = state.writeptr;
while ( (log_size > 0) && while ( (log_size > 0) &&
((logbuf[(log_end-1) & (LOGBUF_SIZE - 1)] == '\n') || ((logbuf[(log_end-1) & (LOGBUF_SIZE - 1)] == '\n') ||
(logbuf[(log_end-1) & (LOGBUF_SIZE - 1)] == ' '))) (logbuf[(log_end-1) & (LOGBUF_SIZE - 1)] == ' ')))
+9 -11
View File
@@ -75,8 +75,7 @@
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
inline void inline void
buf_setup(register __xdata struct psock_buf *buf, buf_setup(__xdata struct psock_buf *buf, __xdata u8_t *bufptr, u16_t bufsize)
register __xdata u8_t *bufptr, register u16_t bufsize)
{ {
buf->ptr = bufptr; buf->ptr = bufptr;
buf->left = bufsize; buf->left = bufsize;
@@ -84,7 +83,7 @@ buf_setup(register __xdata struct psock_buf *buf,
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
inline u8_t inline u8_t
buf_bufdata(register __xdata struct psock_buf *buf, register __xdata u8_t **dataptr, register __xdata u16_t *datalen) buf_bufdata(__xdata struct psock_buf *buf, __xdata u8_t **dataptr, __xdata u16_t *datalen)
{ {
if(*datalen < buf->left) { if(*datalen < buf->left) {
memcpy(buf->ptr, *dataptr, *datalen); memcpy(buf->ptr, *dataptr, *datalen);
@@ -145,7 +144,7 @@ buf_bufto(__xdata struct psock_buf *buf, u8_t endmarker,
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static char static char
send_data(register __xdata struct psock *s) send_data(__xdata struct psock *s)
{ {
if(s->state != STATE_DATA_SENT || uip_rexmit()) { if(s->state != STATE_DATA_SENT || uip_rexmit()) {
if(s->sendlen > uip_mss()) { if(s->sendlen > uip_mss()) {
@@ -160,7 +159,7 @@ send_data(register __xdata struct psock *s)
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static char static char
data_acked(register __xdata struct psock *s) data_acked(__xdata struct psock *s)
{ {
if(s->state == STATE_DATA_SENT && uip_acked()) { if(s->state == STATE_DATA_SENT && uip_acked()) {
if(s->sendlen > uip_mss()) { if(s->sendlen > uip_mss()) {
@@ -176,8 +175,7 @@ data_acked(register __xdata struct psock *s)
return 0; return 0;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
PT_THREAD(psock_send(register __xdata struct psock *s, register __xdata const char *buf, PT_THREAD(psock_send(__xdata struct psock *s, __xdata const char *buf, uint16_t len))
register uint16_t len))
{ {
PT_BEGIN(&s->psockpt); PT_BEGIN(&s->psockpt);
@@ -218,7 +216,7 @@ PT_THREAD(psock_send(register __xdata struct psock *s, register __xdata const ch
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
// PT_THREAD(psock_generator_send(register __xdata struct psock *s, // PT_THREAD(psock_generator_send(__xdata struct psock *s,
// unsigned short (*generate)(void *), void *arg)) // unsigned short (*generate)(void *), void *arg))
// { // {
// PT_BEGIN(&s->psockpt); // PT_BEGIN(&s->psockpt);
@@ -275,7 +273,7 @@ psock_newdata(__xdata struct psock *s)
} }
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
PT_THREAD(psock_readto(register __xdata struct psock *psock, unsigned char c)) PT_THREAD(psock_readto(__xdata struct psock *psock, unsigned char c))
{ {
PT_BEGIN(&psock->psockpt); PT_BEGIN(&psock->psockpt);
@@ -304,7 +302,7 @@ PT_THREAD(psock_readto(register __xdata struct psock *psock, unsigned char c))
PT_END(&psock->psockpt); PT_END(&psock->psockpt);
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
PT_THREAD(psock_readbuf(register __xdata struct psock *psock)) PT_THREAD(psock_readbuf(__xdata struct psock *psock))
{ {
PT_BEGIN(&psock->psockpt); PT_BEGIN(&psock->psockpt);
@@ -334,7 +332,7 @@ PT_THREAD(psock_readbuf(register __xdata struct psock *psock))
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
void void
psock_init(register __xdata struct psock *psock, register __xdata char *buffer, register uint16_t buffersize) psock_init(__xdata struct psock *psock, __xdata char *buffer, uint16_t buffersize)
{ {
psock->state = STATE_NONE; psock->state = STATE_NONE;
psock->readlen = 0; psock->readlen = 0;
+2 -2
View File
@@ -124,7 +124,7 @@ struct psock {
u8_t state; /* The state of the protosocket. */ u8_t state; /* The state of the protosocket. */
}; };
void psock_init(__xdata struct psock *psock, register __xdata char *buffer, register uint16_t buffersize); void psock_init(__xdata struct psock *psock, __xdata char *buffer, uint16_t buffersize);
/** /**
* Initialize a protosocket. * Initialize a protosocket.
* *
@@ -158,7 +158,7 @@ void psock_init(__xdata struct psock *psock, register __xdata char *buffer, regi
*/ */
#define PSOCK_BEGIN(psock) PT_BEGIN(&((psock)->pt)) #define PSOCK_BEGIN(psock) PT_BEGIN(&((psock)->pt))
PT_THREAD(psock_send(register __xdata struct psock *psock, register __xdata const char *buf, register uint16_t len)); PT_THREAD(psock_send(__xdata struct psock *psock, __xdata const char *buf, uint16_t len));
/** /**
* Send data. * Send data.
* *
+6 -6
View File
@@ -157,7 +157,7 @@ __xdata u16_t uip_len, uip_slen;
__xdata u8_t uip_flags; /* The uip_flags variable is used for __xdata u8_t uip_flags; /* The uip_flags variable is used for
communication between the TCP/IP stack communication between the TCP/IP stack
and the application program. */ and the application program. */
__xdata struct uip_conn *uip_conn; /* uip_conn always points to the current __xdata struct uip_conn * __xdata uip_conn; /* uip_conn always points to the current
connection. */ connection. */
__xdata struct uip_conn uip_conns[UIP_CONNS]; __xdata struct uip_conn uip_conns[UIP_CONNS];
@@ -167,7 +167,7 @@ __xdata u16_t uip_listenports[UIP_LISTENPORTS];
/* The uip_listenports list all currently /* The uip_listenports list all currently
listning ports. */ listning ports. */
#if UIP_UDP #if UIP_UDP
__xdata struct uip_udp_conn *uip_udp_conn; __xdata struct uip_udp_conn * __xdata uip_udp_conn;
__xdata struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS]; __xdata struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS];
#endif /* UIP_UDP */ #endif /* UIP_UDP */
@@ -234,7 +234,7 @@ __xdata struct uip_stats uip_stat;
#endif /* UIP_STATISTICS == 1 */ #endif /* UIP_STATISTICS == 1 */
#if UIP_LOGGING == 1 #if UIP_LOGGING == 1
#define UIP_LOG(m) print_string_no_syslog(m); #define UIP_LOG(m) print_string_newline_no_syslog(m);
#else #else
#define UIP_LOG(m) #define UIP_LOG(m)
#endif /* UIP_LOGGING == 1 */ #endif /* UIP_LOGGING == 1 */
@@ -400,7 +400,7 @@ uip_init(void) __banked
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
#if UIP_ACTIVE_OPEN #if UIP_ACTIVE_OPEN
__xdata struct uip_conn * __xdata struct uip_conn *
uip_connect(register __xdata uip_ipaddr_t *ripaddr, __xdata u16_t rport) __banked uip_connect(__xdata uip_ipaddr_t *ripaddr, __xdata u16_t rport) __banked
{ {
__xdata struct uip_conn *conn, *cconn; __xdata struct uip_conn *conn, *cconn;
@@ -466,7 +466,7 @@ uip_connect(register __xdata uip_ipaddr_t *ripaddr, __xdata u16_t rport) __banke
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
#if UIP_UDP #if UIP_UDP
__xdata struct uip_udp_conn * __xdata struct uip_udp_conn *
uip_udp_new(__xdata uip_ipaddr_t *ripaddr, __xdata u16_t rport) __banked uip_udp_new(__xdata uip_ipaddr_t * __xdata ripaddr, __xdata u16_t rport) __banked
{ {
__xdata struct uip_udp_conn *conn; __xdata struct uip_udp_conn *conn;
@@ -677,7 +677,7 @@ uip_add_rcv_nxt(u16_t n)
void void
uip_process(u8_t flag) __banked uip_process(u8_t flag) __banked
{ {
register __xdata struct uip_conn *uip_connr = uip_conn; __xdata struct uip_conn *uip_connr = uip_conn;
#if UIP_UDP #if UIP_UDP
if(flag == UIP_UDP_SEND_CONN) { if(flag == UIP_UDP_SEND_CONN) {
+3 -3
View File
@@ -763,7 +763,7 @@ void uip_send(__xdata const void *data, __xdata uint16_t len) __banked;
* \return The uip_udp_conn structure for the new connection or NULL * \return The uip_udp_conn structure for the new connection or NULL
* if no connection could be allocated. * if no connection could be allocated.
*/ */
__xdata struct uip_udp_conn *uip_udp_new(__xdata uip_ipaddr_t *ripaddr, __xdata u16_t rport) __banked; __xdata struct uip_udp_conn *uip_udp_new(__xdata uip_ipaddr_t * __xdata ripaddr, __xdata u16_t rport) __banked;
/** /**
* Removed a UDP connection. * Removed a UDP connection.
@@ -1193,7 +1193,7 @@ struct uip_conn {
* The uip_conn pointer can be used to access the current TCP * The uip_conn pointer can be used to access the current TCP
* connection. * connection.
*/ */
extern __xdata struct uip_conn *uip_conn; extern __xdata struct uip_conn * __xdata uip_conn;
/* The array containing all uIP connections. */ /* The array containing all uIP connections. */
extern __xdata struct uip_conn uip_conns[UIP_CONNS]; extern __xdata struct uip_conn uip_conns[UIP_CONNS];
/** /**
@@ -1226,7 +1226,7 @@ struct uip_udp_conn {
/** /**
* The current UDP connection. * The current UDP connection.
*/ */
extern __xdata struct uip_udp_conn *uip_udp_conn; extern __xdata struct uip_udp_conn * __xdata uip_udp_conn;
extern __xdata struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS]; extern __xdata struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS];
#endif /* UIP_UDP */ #endif /* UIP_UDP */
+1 -1
View File
@@ -175,7 +175,7 @@ uip_arp_timer(void) __banked
} }
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
static void static void
uip_arp_update(__xdata u16_t *ipaddr, __xdata struct uip_eth_addr *ethaddr) uip_arp_update(__xdata u16_t * __xdata ipaddr, __xdata struct uip_eth_addr * __xdata ethaddr)
{ {
uint8_t i; uint8_t i;
/* Walk through the ARP mapping table and try to find an entry to /* Walk through the ARP mapping table and try to find an entry to