/*
 * $Id: mii_regs.c,v 1.2 2000/03/03 17:30:53 stewart Exp $
 *
 * The program provides an interface to the private ioctls supported
 * by some network drivers.
 *
 * On 'winders, this ioctl is supported on the tulip and the
 * yellowfin, which are always eth1.
 *
 * Usage:   mii_read		- display quick status
 *          mii_read -a   - display all registers
 *          mii_read reg	- display register
 *          mii_read reg value  - write value to register
 *                                you must be superuser to write
 *
 * Sean MacLennan <seanm@rebel.com> Jan 2000
 */

#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <linux/sockios.h>
#include <linux/if.h>


int main(int argc, char *argv[])
{
  int s;
  struct ifreq ifr;
  unsigned short *data = (unsigned short *)&ifr.ifr_data;

  if((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
    perror("socket");
    exit(1);
  }

  strcpy(ifr.ifr_name, "eth1");

  // Get the PHY from the driver - all NetWinders are
  // hardcoded to 1
  if(ioctl(s, SIOCDEVPRIVATE, &ifr) == -1) {
    perror("ioctl");
    exit(1);
  }
  if(data[0] != 1)
    printf("PROBLEMS: PHY should be 1 not %d\n", data[0]);

  if(argc == 3) {
    // Write a register with verify
    // I hope you know what you are doing.....
    unsigned short val;

    data[1] = strtol(argv[1], 0, 0);
    val = data[2] = strtol(argv[2], 0, 0);
    if(ioctl(s, SIOCDEVPRIVATE + 2, &ifr) == -1)
      perror("ioctl write");
    else if(ioctl(s, SIOCDEVPRIVATE + 1, &ifr) == -1)
      perror("ioctl read");
    else if(data[3] != val)
      printf("Write failed. reg %2d = 0x%04x\n", data[1], data[3]);
  }
  else if(argc == 2) {
    if(strcmp(argv[1], "-a") == 0 || strcmp(argv[1], "-v") == 0) {
      for(data[1] = 0; data[1] < 16; ++data[1]) {
        if(ioctl(s, SIOCDEVPRIVATE + 1, &ifr) == -1)
          perror("ioctl");
        else
          printf("\treg %2d = 0x%04x\t\t", data[1], data[3]);
        data[1] += 16;
        if(ioctl(s, SIOCDEVPRIVATE + 1, &ifr) == -1)
          perror("ioctl");
        else
          printf("reg %2d = 0x%04x\n", data[1], data[3]);
        data[1] -= 16;
      }
    }
    else {
      // Read a register
      data[1] = strtol(argv[1], 0, 0);
      if(ioctl(s, SIOCDEVPRIVATE + 1, &ifr) == -1)
        perror("ioctl");
      else
        printf("reg %2d = 0x%04x\n", data[1], data[3]);
    }
  }
  else {
    // Quick status
    data[1] = 17;
    if(ioctl(s, SIOCDEVPRIVATE + 1, &ifr) == -1)
      perror("ioctl");
    else if(data[3] == 0xffff)
      printf("ERROR: Unable to read MII register\n");
    else if(data[3] & 1)
      printf("0x%04x = Link %d Mb/s %s duplex\n",
	     data[3], (data[3] & 0x8000) ? 100 : 10,
	     (data[3] & 0x4000) ? "full" : "half");
    else
      printf("0x%04x = Link down\n", data[3]);
  }

  close(s);

  return 0;
}

/*
 * Local variables:
 *  compile-command: "gcc -O6 -static -o mii_regs mii_regs.c"
 * End:
 */

