# 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
