diff options
Diffstat (limited to 'zap-phy.c')
-rw-r--r-- | zap-phy.c | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/zap-phy.c b/zap-phy.c new file mode 100644 index 0000000..c4dc7eb --- /dev/null +++ b/zap-phy.c @@ -0,0 +1,172 @@ +#include <curses.h> +#include <errno.h> +#include <limits.h> +#include <stdlib.h> +#include <string.h> +#include <sys/fcntl.h> +#include <unistd.h> + +#include "zap.h" + +extern int mdio_read(long ioaddr, int phy_id, int mii_reg_num); +extern void mdio_write(int ioaddr, int phy_id, int location, int value); + +struct zap_phy { + long ioaddr; + int phy_id; + int devad; + int irq_fd; + char aux_buf[16]; +}; + +static bool phy_read(void *private, u32 addr, u32 *val) +{ + struct zap_phy *phy = private; + int v; + + v = mdio_read(phy->ioaddr, phy->phy_id | phy->devad, addr); + + *val = v >= 0 ? v : 0; + + return v >= 0; +} + +static void phy_write(void *private, u32 addr, u32 val) +{ + struct zap_phy *phy = private; + + mdio_write(phy->ioaddr, phy->phy_id | phy->devad, addr, val); +} + +static void phy_c45_key(struct zap_private *priv, void *private, int key) +{ + struct zap_phy *phy = private; + int val; + + switch (key) { + case 'r': + val = mdio_read(phy->ioaddr, phy->phy_id | 7, 0); + if (val < 0) + return; + mdio_write(phy->ioaddr, phy->phy_id | 7, 0, val | 0x200); + break; + + case 'p': + zap_prompt_input(priv, 'p', "PHY devad"); + break; + } +} + +static void phy_c45_print_unit(void *private) +{ + struct zap_phy *phy = private; + const char *dev = ""; + + switch (phy->devad) { + case 1: dev = " PMA/PMD"; break; + case 2: dev = " WIS"; break; + case 3: dev = " PCS"; break; + case 4: dev = " PHYXS"; break; + case 5: dev = " DTEXS"; break; + case 7: dev = " AN"; break; + } + + printw("PHY #%u.%-2u%s", (phy->phy_id >> 5) & 31, phy->devad, dev); + clrtoeol(); +} + +static void phy_c45_update_aux(void *private) +{ + struct zap_phy *phy = private; + char new[16]; + int len; + + if (phy->irq_fd == -1) + return; + + lseek(phy->irq_fd, 0, SEEK_SET); + len = read(phy->irq_fd, new, sizeof(new)); + if (len < 0 || len >= sizeof(new)) + return; + + len -= 1; + + if (!memcmp(phy->aux_buf, new, len)) + return; + + memcpy(phy->aux_buf, new, len); + mvprintw(1, 41, "IRQ "); + mvaddnstr(1, 45, new, len); + clrtoeol(); +} + +static void phy_c45_input(void *private, char mode, const char *buf) +{ + struct zap_phy *phy = private; + unsigned long unit; + + errno = 0; + unit = strtoul(buf, NULL, 0); + if (unit == ULONG_MAX && errno == ERANGE) + return; + if (unit > 31) + return; + + phy->devad = unit; +} + +static const struct zap phy_c45_zap = { + .val_width = 4, + .max_addr = 0xffff, + .read = phy_read, + .write = phy_write, + .key = phy_c45_key, + .print_header = phy_c45_print_unit, + .update_aux = phy_c45_update_aux, + .input = phy_c45_input, +}; + +static void phy_print_c22_unit(void *private) +{ + struct zap_phy *phy = private; + + printw("PHY #%u", phy->phy_id); +} + +static const struct zap phy_c22_zap = { + .val_width = 4, + .max_addr = 0x1f, + .read = phy_read, + .write = phy_write, + .print_header = phy_print_c22_unit, +}; + + +void phy_zap(long ioaddr, int phy_id, unsigned long start) +{ + const struct zap *z; + struct zap_phy phy = { + .ioaddr = ioaddr, + .irq_fd = -1, + }; + + if (phy_id & 0x8000) { + phy.phy_id = phy_id & ~31; + phy.devad = phy_id & 31; + + if (phy_id == 0x8000) + phy.irq_fd = open("/sys/class/gpio/gpio82/value", O_RDONLY); + else if (phy_id == 0x8000 + 8 * 32) + phy.irq_fd = open("/sys/class/gpio/gpio81/value", O_RDONLY); + + z = &phy_c45_zap; + } else { + phy.phy_id = phy_id; + phy.devad = 0; + + z = &phy_c22_zap; + } + if (start >= z->max_addr) + start = z->max_addr; + zap(z, start, &phy); +} |