LAN7800 EEPROM Programmer
Public Made by Adomby adom
MPLAB-Connect-parity EEPROM tool for the Microchip LAN7800 USB-3.1 to Gigabit-Ethernet controller (VID 0x0424 / PID 0x7800). Read an adapter's EEPROM to a .bin, edit MAC / VID / PID / bcdDevice / strings / serial and LED/GPIO with a byte-exact preview, and program hardware with verify-after-write. Reads are free; physical writes are gated behind --force-physical-write. Ships an AI-oriented CLI (single source of truth) plus a Hydrogen webapp that shells out to it.
LAN7800 EEPROM programming on Linux — mechanism reference
Source: CONDUCTOR research scout, verified against Linux kernel source, LAN7800 datasheet DS00001992G, and u-boot. LAN7800 only (USB VID 0x0424 / PID 0x7800).
Two backends
A. Kernel driver + ethtool (RECOMMENDED primary)
drivers/net/usb/lan78xx.c implements ethtool EEPROM ops.
- Constants:
LAN78XX_EEPROM_MAGIC 0x78A5,OTP_MAGIC 0x78F3,MAX_EEPROM_SIZE 512,EEPROM_INDICATOR 0xA5,EEPROM_MAC_OFFSET 0x01, OTP indicators0xF3/0xF7. - Read:
ethtool -e <iface> [raw on] [offset N length M]. Reading a blank/unsigned EEPROM returns-ENODATA(offset 0 != 0xA5) — not zeros. - Write:
ethtool -E <iface> magic 0x78A5 offset <o> value <v>— one byte per call. The driver issues EWEN internally; you do NOT manage EWEN/EWDS on this path. - Quirks: 512-byte max; 9-bit address (0–511); no signature check on write (you own writing 0xA5); reset/replug to reload the image (avoid raw RELOAD).
B. libusb vendor commands (only if driver-independence / blank-chip needed)
Unbind the kernel driver first. Two vendor control transfers:
- Read reg: bmRequestType
0xC0, bRequest0xA1, wValue 0, wIndex=reg offset, 4-byte LE. - Write reg: bmRequestType
0x40, bRequest0xA0, wValue 0, wIndex=reg offset, 4-byte LE. Registers:HW_CFG 0x010,E2P_CMD 0x040,E2P_DATA 0x044. E2P_CMD bits:BUSY 0x80000000, cmd field bits 30:28 — READ 0x0, EWDS 0x1<<28, EWEN 0x2<<28, WRITE 0x3<<28, WRAL 0x4<<28, ERASE 0x5<<28, ERAL 0x6<<28, RELOAD 0x7<<28;TIMEOUT 0x400,DL 0x200,ADDR_MASK 0x1FF. - Read byte A: write E2P_CMD = BUSY|READ|A; poll BUSY clear; read E2P_DATA[7:0].
- Write byte D@A: EWEN once (BUSY|EWEN, poll); write E2P_DATA=D; write E2P_CMD=BUSY|WRITE|A (poll); repeat; EWDS when done. You must issue EWEN yourself on this path.
EEPROM binary layout (datasheet Table 10-2, byte offsets)
- 0x00:
0xA5signature (device ignores EEPROM if != 0xA5 → falls back to OTP/defaults) - 0x01–0x06: MAC, LE octet order — MAC AA:BB:CC:DD:EE:FF → bytes FF EE DD CC BB AA (VERIFY direction against a real dump + datasheet §15.1.54 before trusting.)
- 0x07: GPIO wakeup enables; 0x09–0x0A GPIO PME flags; 0x0B–0x0D LED config 0/1/2
- 0x0E: GPIO wakeup polarity; 0x10–0x12 interrupt-EP polling (FS/HS/SS)
- 0x13–0x22: Config Flags 0–3 (4 bytes each, LE)
- 0x23–0x24: Language ID; 0x25–0x2E string desc len+word-offset pairs (Mfr, Product, Serial, Config, Interface). VID/PID live INSIDE the SS/HS/FS device-descriptor blocks (pointed to by 0x31/0x35/0x39), idVendor at desc bytes 8–9, idProduct 10–11, LE.
- Pointer fields are in 16-bit WORD units; length 0 = field absent → hardware default.
Boot precedence
valid EEPROM → configured OTP → CSR defaults. USB reset reloads MAC only; full load on POR/RESET/SRST.
Safe procedure (ethtool path)
- Back up full EEPROM first:
sudo ethtool -e <iface> raw on > eeprom-backup.bin - Confirm byte 0 == A5; MAC at 0x01–0x06.
- Edit only the 6 MAC bytes on a COPY.
- Write per-byte with magic 0x78A5.
- Replug / usb reset to reload.
- Verify: re-read, diff against intended image;
ip linkshows new MAC.
Anti-brick: never touch 0x00 unless deliberately writing 0xA5; stay 0–511; change the minimum bytes; keep the backup; a cleared/!=A5 signature is recoverable (falls back).
References
- linux drivers/net/usb/lan78xx.c + lan78xx.h (authoritative register map)
- LAN7800 Data Sheet DS00001992G §10.0–10.4, Table 10-2, §15.1.54
- u-boot drivers/usb/eth/lan78xx.c ; microchip-ung/lan78xx_linux
- Template libusb scaffolding (different chip, reuse structure only): karosium/asix_eepromtool, jglim/ASIXFlash
# LAN7800 EEPROM programming on Linux — mechanism reference
Source: CONDUCTOR research scout, verified against Linux kernel source, LAN7800
datasheet DS00001992G, and u-boot. LAN7800 only (USB VID 0x0424 / PID 0x7800).
## Two backends
### A. Kernel driver + ethtool (RECOMMENDED primary)
`drivers/net/usb/lan78xx.c` implements ethtool EEPROM ops.
- Constants: `LAN78XX_EEPROM_MAGIC 0x78A5`, `OTP_MAGIC 0x78F3`, `MAX_EEPROM_SIZE 512`,
`EEPROM_INDICATOR 0xA5`, `EEPROM_MAC_OFFSET 0x01`, OTP indicators `0xF3`/`0xF7`.
- Read: `ethtool -e <iface> [raw on] [offset N length M]`. Reading a blank/unsigned
EEPROM returns `-ENODATA` (offset 0 != 0xA5) — not zeros.
- Write: `ethtool -E <iface> magic 0x78A5 offset <o> value <v>` — one byte per call.
The driver issues EWEN internally; you do NOT manage EWEN/EWDS on this path.
- Quirks: 512-byte max; 9-bit address (0–511); no signature check on write (you own
writing 0xA5); reset/replug to reload the image (avoid raw RELOAD).
### B. libusb vendor commands (only if driver-independence / blank-chip needed)
Unbind the kernel driver first. Two vendor control transfers:
- Read reg: bmRequestType `0xC0`, bRequest `0xA1`, wValue 0, wIndex=reg offset, 4-byte LE.
- Write reg: bmRequestType `0x40`, bRequest `0xA0`, wValue 0, wIndex=reg offset, 4-byte LE.
Registers: `HW_CFG 0x010`, `E2P_CMD 0x040`, `E2P_DATA 0x044`.
E2P_CMD bits: `BUSY 0x80000000`, cmd field bits 30:28 — READ 0x0, EWDS 0x1<<28,
EWEN 0x2<<28, WRITE 0x3<<28, WRAL 0x4<<28, ERASE 0x5<<28, ERAL 0x6<<28, RELOAD 0x7<<28;
`TIMEOUT 0x400`, `DL 0x200`, `ADDR_MASK 0x1FF`.
- Read byte A: write E2P_CMD = BUSY|READ|A; poll BUSY clear; read E2P_DATA[7:0].
- Write byte D@A: EWEN once (BUSY|EWEN, poll); write E2P_DATA=D; write E2P_CMD=BUSY|WRITE|A
(poll); repeat; EWDS when done. **You must issue EWEN yourself on this path.**
## EEPROM binary layout (datasheet Table 10-2, byte offsets)
- 0x00: `0xA5` signature (device ignores EEPROM if != 0xA5 → falls back to OTP/defaults)
- 0x01–0x06: MAC, **LE octet order** — MAC AA:BB:CC:DD:EE:FF → bytes FF EE DD CC BB AA
(VERIFY direction against a real dump + datasheet §15.1.54 before trusting.)
- 0x07: GPIO wakeup enables; 0x09–0x0A GPIO PME flags; 0x0B–0x0D LED config 0/1/2
- 0x0E: GPIO wakeup polarity; 0x10–0x12 interrupt-EP polling (FS/HS/SS)
- 0x13–0x22: Config Flags 0–3 (4 bytes each, LE)
- 0x23–0x24: Language ID; 0x25–0x2E string desc len+word-offset pairs (Mfr, Product,
Serial, Config, Interface). VID/PID live INSIDE the SS/HS/FS device-descriptor blocks
(pointed to by 0x31/0x35/0x39), idVendor at desc bytes 8–9, idProduct 10–11, LE.
- Pointer fields are in 16-bit WORD units; length 0 = field absent → hardware default.
## Boot precedence
valid EEPROM → configured OTP → CSR defaults. USB reset reloads MAC only; full load on POR/RESET/SRST.
## Safe procedure (ethtool path)
1. Back up full EEPROM first: `sudo ethtool -e <iface> raw on > eeprom-backup.bin`
2. Confirm byte 0 == A5; MAC at 0x01–0x06.
3. Edit only the 6 MAC bytes on a COPY.
4. Write per-byte with magic 0x78A5.
5. Replug / usb reset to reload.
6. Verify: re-read, diff against intended image; `ip link` shows new MAC.
Anti-brick: never touch 0x00 unless deliberately writing 0xA5; stay 0–511; change the
minimum bytes; keep the backup; a cleared/!=A5 signature is recoverable (falls back).
## References
- linux drivers/net/usb/lan78xx.c + lan78xx.h (authoritative register map)
- LAN7800 Data Sheet DS00001992G §10.0–10.4, Table 10-2, §15.1.54
- u-boot drivers/usb/eth/lan78xx.c ; microchip-ung/lan78xx_linux
- Template libusb scaffolding (different chip, reuse structure only): karosium/asix_eepromtool, jglim/ASIXFlash