724487e
/* Mode: C;
724487e
 * mii-diag.c: Examine and set the MII registers of a network interfaces.
724487e
724487e
	Usage:	mii-diag [-vw] interface.
724487e
724487e
	This program reads and writes the Media Independent Interface (MII)
724487e
	management registers on network transceivers.  The registers control
724487e
	and report network link settings and errors.  Examples are link speed,
724487e
	duplex, capabilities advertised to the link partner, status LED
724487e
	indications and link error counters.
724487e
724487e
	Notes:
724487e
	The compile-command is at the end of this source file.
724487e
	This program works with drivers that implement MII ioctl() calls.
724487e
724487e
	Written/copyright 1997-2003 by Donald Becker <becker@scyld.com>
724487e
724487e
	This program is free software; you can redistribute it
724487e
	and/or modify it under the terms of the GNU General Public
724487e
	License as published by the Free Software Foundation.
724487e
724487e
	The author may be reached as becker@scyld.com, or C/O
724487e
	 Scyld Computing Corporation
724487e
	 914 Bay Ridge Road, Suite 220
724487e
	 Annapolis MD 21403
724487e
724487e
	References
724487e
	http://scyld.com/expert/mii-status.html
724487e
	http://scyld.com/expert/NWay.html
724487e
	http://www.national.com/pf/DP/DP83840.html
724487e
*/
724487e
724487e
static char version[] =
724487e
"mii-diag.c:v2.11 3/21/2005 Donald Becker (becker@scyld.com)\n"
724487e
" http://www.scyld.com/diag/index.html\n";
724487e
724487e
static const char usage_msg[] =
3ecd878
"Usage: %s [--help] [-aDfrRvVw] [-AF <speed+duplex>] [--watch] <interface>\n";
724487e
static const char long_usage_msg[] =
3ecd878
"Usage: %s [-aDfrRvVw] [-AF <speed+duplex>] [--watch] <interface>\n\
724487e
\n\
724487e
  This program configures and monitors the transceiver management registers\n\
724487e
  for network interfaces.  It uses the Media Independent Interface (MII)\n\
724487e
  standard with additional Linux-specific controls to communicate with the\n\
724487e
  underlying device driver.  The MII registers control and report network\n\
724487e
  link settings and errors.  Examples are link speed, duplex, capabilities\n\
724487e
  advertised to the link partner, status LED indications and link error\n\
724487e
  counters.\n\
724487e
\n\
724487e
   The common usage is\n\
724487e
      mii-diag eth0\n\
724487e
\n\
724487e
 Frequently used options are\n\
724487e
   -A  --advertise <speed|setting>\n\
724487e
   -F  --fixed-speed <speed>\n\
724487e
	Speed is one of: 100baseT4, 100baseTx, 100baseTx-FD, 100baseTx-HD,\n\
724487e
	                 10baseT, 10baseT-FD, 10baseT-HD\n\
724487e
   -s  --status     Return exit status 2 if there is no link beat.\n\
724487e
\n\
724487e
 Less frequently used options are\n\
724487e
   -a  --all-interfaces  Show the status all interfaces\n\
724487e
              (Not recommended with options that change settings.)\n\
724487e
   -D  --debug\n\
724487e
   -g  --read-parameters 	Get driver-specific parameters.\n\
724487e
   -G  --set-parameters PARMS	Set driver-specific parameters.\n\
724487e
       Parameters are comma separated, missing parameters retain\n\
724487e
       their previous values.\n\
724487e
   -M  --msg-level LEVEL 	Set the driver message bit map.\n\
724487e
   -p  --phy ADDR		Set the PHY (MII address) to report.\n\
724487e
   -r  --restart	Restart the link autonegotiation.\n\
724487e
   -R  --reset		Reset the transceiver.\n\
724487e
   -v  --verbose	Report each action taken.\n\
724487e
   -V  --version	Emit version information.\n\
724487e
   -w  --watch		Continuously monitor the transceiver and report changes.\n\
724487e
\n\
724487e
   This command returns success (zero) if the interface information can be\n\
724487e
   read.  If the --status option is passed, a zero return means that the\n\
724487e
   interface has link beat.\n\
724487e
";
724487e
724487e
#include <unistd.h>
724487e
#include <stdlib.h>
724487e
#include <stdio.h>
724487e
#include <ctype.h>
724487e
#include <string.h>
724487e
#include <errno.h>
724487e
#include <fcntl.h>
724487e
#include <getopt.h>
724487e
#include <sys/types.h>
724487e
#include <sys/socket.h>
724487e
#include <sys/ioctl.h>
724487e
#include <net/if.h>
724487e
#ifdef use_linux_libc5
724487e
#include <linux/if_arp.h>
724487e
#include <linux/if_ether.h>
724487e
#endif
724487e
724487e
typedef u_int32_t u32;
724487e
typedef u_int16_t u16;
724487e
typedef u_int8_t u8;
724487e
724487e
#if defined(SIOCGPARAMS)  && SIOCGPARAMS != SIOCDEVPRIVATE+3
724487e
#error Changed definition for SIOCGPARAMS
724487e
#else
724487e
#define SIOCGPARAMS (SIOCDEVPRIVATE+3) 		/* Read operational parameters. */
724487e
#define SIOCSPARAMS (SIOCDEVPRIVATE+4) 		/* Set operational parameters. */
724487e
#endif
724487e
724487e
const char shortopts[] = "aA:C:DfF:gG:hmM:p:rRsvVw?";
724487e
struct option longopts[] = {
724487e
 /* { name  has_arg  *flag  val } */
724487e
    {"all-interfaces", 0, 0, 'a'},	/* Show all interfaces. */
724487e
	{"advertise",	1, 0, 'A'},		/* Change the capabilities advertised. */
724487e
	{"BMCR",		1, 0, 'C'},		/* Set the control register. */
724487e
    {"debug",       0, 0, 'D'},		/* Increase the debug level. */
724487e
    {"force",       0, 0, 'f'},		/* Force the operation. */
724487e
    {"fixed-speed", 1, 0, 'F'},		/* Fixed speed name. */
724487e
    {"read-parameters", 0, 0, 'g'}, /* Show general settings values. */
724487e
    {"set-parameters",  1, 0, 'G'},	/* Write general settings values. */
724487e
    {"help", 		0, 0, 'h'},		/* Print a long usage message. */
724487e
    {"monitor",		0, 0, 'm'},		/* Monitor status register. */
724487e
    {"msg-level",	1, 0, 'M'},		/* Set the driver message level. */
724487e
    {"phy",			1, 0, 'p'},		/* Set the PHY (MII address) to report. */
724487e
    {"restart",		0, 0, 'r'},		/* Restart the link negotiation */
724487e
    {"reset",		0, 0, 'R'},		/* Reset the transceiver. */
724487e
    {"status",		0, 0, 's'},		/* Non-zero exit status w/ no link beat. */
724487e
    {"verbose", 	0, 0, 'v'},		/* Report each action taken.  */
724487e
    {"version", 	0, 0, 'V'},		/* Emit version information.  */
724487e
    {"watch", 		0, 0, 'w'},		/* Constantly monitor the port.  */
724487e
    {"error", 		0, 0, '?'},		/* Return the error message. */
724487e
    { 0, 0, 0, 0 }
724487e
};
724487e
724487e
/* Usually in libmii.c, but trivial substitions are below. */
724487e
extern int  show_mii_details(long ioaddr, int phy_id);
724487e
extern void monitor_mii(long ioaddr, int phy_id);
724487e
int  show_mii_details(long ioaddr, int phy_id) __attribute__((weak));
724487e
void monitor_mii(long ioaddr, int phy_id) __attribute__((weak));
724487e
724487e
724487e
/* Command-line flags. */
724487e
unsigned int opt_a = 0,					/* Show-all-interfaces flag. */
724487e
	opt_f = 0,					/* Force the operation. */
724487e
	opt_g = 0,
724487e
	opt_G = 0,
724487e
	verbose = 0,				/* Verbose flag. */
724487e
	debug = 0,
724487e
	opt_version = 0,
724487e
	opt_restart = 0,
724487e
	opt_reset = 0,
724487e
	opt_status = 0,
724487e
	opt_watch = 0;
724487e
static int msg_level = -1;
724487e
static int set_BMCR = -1;
724487e
static int nway_advertise = 0;
724487e
static int fixed_speed = -1;
724487e
static int override_phy = -1;
724487e
char *opt_G_string = NULL;
724487e
724487e
/* Internal values. */
724487e
int new_ioctl_nums;
724487e
int skfd = -1;					/* AF_INET socket for ioctl() calls.	*/
724487e
struct ifreq ifr;
724487e
724487e
int do_one_xcvr(int skfd);
724487e
int show_basic_mii(long ioaddr, int phy_id);
724487e
int mdio_read(int skfd, int phy_id, int location);
724487e
void mdio_write(int skfd, int phy_id, int location, int value);
724487e
static int parse_advertise(const char *capabilities);
724487e
static void monitor_status(long ioaddr, int phy_id);
724487e
724487e
724487e
int
724487e
main(int argc, char **argv)
724487e
{
724487e
	int c, errflag = 0;
724487e
	char **spp, *ifname;
724487e
    char *progname = rindex(argv[0], '/') ? rindex(argv[0], '/')+1 : argv[0];
724487e
724487e
	while ((c = getopt_long(argc, argv, shortopts, longopts, 0)) != EOF)
724487e
		switch (c) {
724487e
		case 'a': opt_a++; break;
724487e
		case 'A': nway_advertise |= parse_advertise(optarg);
724487e
			if (nway_advertise == -1) errflag++;
724487e
			break;
724487e
		case 'C': set_BMCR = strtoul(optarg, NULL, 16); break;
724487e
		case 'D': debug++;			break;
724487e
		case 'f': opt_f++; break;
724487e
		case 'F': fixed_speed = parse_advertise(optarg);
724487e
			if (fixed_speed == -1) errflag++;
724487e
			break;
724487e
		case 'g': opt_g++; break;
724487e
		case 'G': opt_G++; opt_G_string = strdup(optarg); break;
724487e
		case 'm': opt_watch++; opt_status++; break;
724487e
		case 'M': msg_level = strtoul(optarg, NULL, 0); break;
724487e
		case 'h': fprintf(stderr, long_usage_msg, progname); return 0;
724487e
		case 'p': override_phy = atoi(optarg); break;
724487e
		case 'r': opt_restart++;	break;
724487e
		case 'R': opt_reset++;		break;
724487e
		case 's': opt_status++;		break;
724487e
		case 'v': verbose++;		break;
724487e
		case 'V': opt_version++;	break;
724487e
		case 'w': opt_watch++;		break;
724487e
		case '?': errflag++;		break;
724487e
		}
724487e
	if (errflag) {
724487e
		fprintf(stderr, usage_msg, progname);
724487e
		return 2;
724487e
	}
724487e
724487e
	if (verbose || opt_version)
724487e
		printf(version);
724487e
724487e
	/* Open a basic socket. */
724487e
	if ((skfd = socket(AF_INET, SOCK_DGRAM,0)) < 0) {
724487e
		perror("socket");
724487e
		return 1;
724487e
	}
724487e
724487e
	if (debug)
724487e
		fprintf(stderr, "DEBUG: argc=%d, optind=%d and argv[optind] is %s.\n",
724487e
				argc, optind, argv[optind]);
724487e
3ecd878
	/* No remaining args means interface wasn't specified. */
724487e
	if (optind == argc) {
3ecd878
		fprintf(stderr, "No interface specified.\n");
3ecd878
		fprintf(stderr, usage_msg, progname);
3ecd878
		(void) close(skfd);
3ecd878
		return 2;
724487e
	} else {
724487e
		/* Copy the interface name. */
724487e
		spp = argv + optind;
724487e
		ifname = *spp++;
724487e
	}
724487e
724487e
	if (ifname == NULL) {
3ecd878
		fprintf(stderr, "No ifname.\n");
3ecd878
		(void) close(skfd);
3ecd878
		return -1;
724487e
	}
724487e
724487e
	/* Verify that the interface supports the ioctl(), and if
724487e
	   it is using the new or old SIOCGMIIPHY value (grrr...).
724487e
	 */
724487e
	{
724487e
		u16 *data = (u16 *)(&ifr.ifr_data);
724487e
724487e
		strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
724487e
		data[0] = 0;
724487e
724487e
		if (ioctl(skfd, 0x8947, &ifr) >= 0) {
724487e
			new_ioctl_nums = 1;
724487e
		} else if (ioctl(skfd, SIOCDEVPRIVATE, &ifr) >= 0) {
724487e
			new_ioctl_nums = 0;
724487e
		} else {
724487e
			fprintf(stderr, "SIOCGMIIPHY on %s failed: %s\n", ifname,
724487e
					strerror(errno));
724487e
			(void) close(skfd);
724487e
			return 1;
724487e
		}
724487e
		if (verbose)
724487e
			printf("  Using the %s SIOCGMIIPHY value on PHY %d "
724487e
				   "(BMCR 0x%4.4x).\n",
724487e
				   new_ioctl_nums ? "new" : "old", data[0], data[3]);
724487e
	}
724487e
724487e
	do_one_xcvr(skfd);
724487e
724487e
	(void) close(skfd);
724487e
	return 0;
724487e
}
724487e
724487e
int do_one_xcvr(int skfd)
724487e
{
724487e
	u16 *data = (u16 *)(&ifr.ifr_data);
724487e
	u32 *data32 = (u32 *)(&ifr.ifr_data);
724487e
	unsigned phy_id = data[0];
724487e
724487e
	if (override_phy >= 0) {
724487e
		printf("Using the specified MII PHY index %d.\n", override_phy);
724487e
		phy_id = override_phy;
724487e
	}
724487e
724487e
	if (opt_g || opt_G || msg_level >= 0) {
724487e
		if (ioctl(skfd, SIOCGPARAMS, &ifr) < 0) {
724487e
			fprintf(stderr, "SIOCGPARAMS on %s failed: %s\n", ifr.ifr_name,
724487e
					strerror(errno));
724487e
			return -1;
724487e
		}
724487e
	}
724487e
	if (opt_g) {
724487e
		int i;
724487e
		printf("Driver general parameter settings:");
724487e
		for (i = 0; i*sizeof(u32) < sizeof(ifr.ifr_ifru); i++) {
724487e
			printf(" %d", data32[i]);
724487e
		}
724487e
		printf(".\n");
724487e
	}
724487e
	if (opt_G) {
724487e
		/* Set up to four arbitrary driver parameters from the -G parameter.
724487e
		   The format is comma separated integers, with a missing element
724487e
		   retaining the previous value.
724487e
		*/
724487e
		char *str = opt_G_string;
724487e
		int i;
724487e
		for (i = 0; str && i < 4; i++) {
724487e
			char *endstr;
724487e
			u32 newval = strtol(str, &endstr, 0);
724487e
			if (debug)
724487e
				printf(" parse string '%s'  value %d end '%s'.\n",
724487e
					   str, newval, endstr);
724487e
			if (str == endstr) {
724487e
				if (endstr[0] == ',') /* No parameter */
724487e
					str = endstr+1;
724487e
				else {
724487e
					fprintf(stderr, "Invalid driver parameter '%s'.\n", str);
724487e
					str = index(str, ',');
724487e
				}
724487e
			} else if (endstr[0] == ',') {
724487e
				data32[i] = newval;
724487e
				str = endstr + 1;
724487e
			} else if (endstr[0] == 0) {
724487e
				data32[i] = newval;
724487e
				break;
724487e
			}
724487e
		}
724487e
		printf("Setting new driver general parameters:");
724487e
		for (i = 0; i*sizeof(u32) < sizeof(ifr.ifr_ifru); i++) {
724487e
			printf(" %d", data32[i]);
724487e
		}
724487e
		printf(".\n");
724487e
		if (ioctl(skfd, SIOCSPARAMS, &ifr) < 0) {
724487e
			fprintf(stderr, "SIOCSPARAMS on %s failed: %s\n", ifr.ifr_name,
724487e
					strerror(errno));
724487e
			return -1;
724487e
		}
724487e
	}
724487e
	if (msg_level >= 0) {
724487e
		data32[0] = msg_level;
724487e
		if (ioctl(skfd, SIOCSPARAMS, &ifr) < 0) {
724487e
			fprintf(stderr, "SIOCSPARAMS on %s failed: %s\n", ifr.ifr_name,
724487e
					strerror(errno));
724487e
			return -1;
724487e
		}
724487e
	}
724487e
724487e
	if (opt_reset) {
724487e
		printf("Resetting the transceiver...\n");
724487e
		mdio_write(skfd, phy_id, 0, 0x8000);
724487e
	}
724487e
	/* Note: PHY addresses > 32 are pseudo-MII devices, usually built-in. */
724487e
	if (phy_id < 64  &&  nway_advertise > 0) {
724487e
		printf(" Setting the media capability advertisement register of "
724487e
			   "PHY #%d to 0x%4.4x.\n", phy_id, nway_advertise | 1);
724487e
		mdio_write(skfd, phy_id, 4, nway_advertise | 1);
724487e
		mdio_write(skfd, phy_id, 0, 0x1000);
724487e
	}
724487e
724487e
	if (opt_restart) {
724487e
		printf("Restarting negotiation...\n");
724487e
		mdio_write(skfd, phy_id, 0, 0x0000);
724487e
		mdio_write(skfd, phy_id, 0, 0x1200);
724487e
	}
724487e
	/* To force 100baseTx-HD do  mdio_write(skfd, phy_id, 0, 0x2000); */
724487e
	if (fixed_speed >= 0) {
724487e
		int reg0_val = 0;
724487e
		if (fixed_speed & 0x0180) 		/* 100mpbs */
724487e
			reg0_val |=  0x2000;
724487e
		if ((fixed_speed & 0x0140) &&		/* A full duplex type and */
724487e
			! (fixed_speed & 0x0820)) 		/* no half duplex types. */
724487e
			reg0_val |= 0x0100;
724487e
		printf("Setting the speed to \"fixed\", Control register %4.4x.\n",
724487e
			   reg0_val);
724487e
		mdio_write(skfd, phy_id, 0, reg0_val);
724487e
	}
724487e
	if (set_BMCR >= 0) {
724487e
		printf("Setting the Basic Mode Control Register to 0x%4.4x.\n",
724487e
			   set_BMCR);
724487e
		mdio_write(skfd, phy_id, 0, set_BMCR);
724487e
	}
724487e
724487e
	if (opt_watch && opt_status)
724487e
		monitor_status(skfd, phy_id);
724487e
724487e
	show_basic_mii(skfd, phy_id);
724487e
#ifdef LIBMII
724487e
	if (verbose)
724487e
		show_mii_details(skfd, phy_id);
724487e
#else
724487e
	if (verbose || debug) {
724487e
		int mii_reg, mii_val;
724487e
		printf(" MII PHY #%d transceiver registers:", phy_id);
724487e
		for (mii_reg = 0; mii_reg < 32; mii_reg++) {
724487e
			mii_val = mdio_read(skfd, phy_id, mii_reg);
724487e
			printf("%s %4.4x", (mii_reg % 8) == 0 ? "\n  " : "",
724487e
				   mii_val);
724487e
		}
724487e
		printf("\n");
724487e
	}
724487e
#endif
724487e
724487e
	if (opt_watch)
724487e
		monitor_mii(skfd, phy_id);
724487e
	if (opt_status &&
724487e
		(mdio_read(skfd, phy_id, 1) & 0x0004) == 0)
724487e
		exit(2);
724487e
	return 0;
724487e
}
724487e
724487e
int mdio_read(int skfd, int phy_id, int location)
724487e
{
724487e
	u16 *data = (u16 *)(&ifr.ifr_data);
724487e
724487e
	data[0] = phy_id;
724487e
	data[1] = location;
724487e
724487e
	if (ioctl(skfd, new_ioctl_nums ? 0x8948 : SIOCDEVPRIVATE+1, &ifr) < 0) {
724487e
		fprintf(stderr, "SIOCGMIIREG on %s failed: %s\n", ifr.ifr_name,
724487e
				strerror(errno));
724487e
		return -1;
724487e
	}
724487e
	return data[3];
724487e
}
724487e
724487e
void mdio_write(int skfd, int phy_id, int location, int value)
724487e
{
724487e
	u16 *data = (u16 *)(&ifr.ifr_data);
724487e
724487e
	data[0] = phy_id;
724487e
	data[1] = location;
724487e
	data[2] = value;
724487e
724487e
	if (ioctl(skfd, new_ioctl_nums ? 0x8949 : SIOCDEVPRIVATE+2, &ifr) < 0) {
724487e
		fprintf(stderr, "SIOCSMIIREG on %s failed: %s\n", ifr.ifr_name,
724487e
				strerror(errno));
724487e
	}
724487e
}
724487e
724487e
/* Parse the command line argument for advertised capabilities. */
724487e
static int parse_advertise(const char *capabilities)
724487e
{
724487e
	const char *mtypes[] = {
724487e
		"100baseT4", "100baseTx", "100baseTx-FD", "100baseTx-HD",
724487e
		"10baseT", "10baseT-FD", "10baseT-HD", 0,
724487e
	};
724487e
	char *endptr;
724487e
	int cap_map[] = { 0x0200, 0x0180, 0x0100, 0x0080, 0x0060, 0x0040, 0x0020,};
724487e
	int i;
724487e
	if ( ! capabilities) {
724487e
		fprintf(stderr, "You passed -A 'NULL'.  You must provide a media"
724487e
				" list to advertise!\n");
724487e
		return -1;
724487e
	}
724487e
	if (debug)
724487e
		fprintf(stderr, "Advertise string is '%s'.\n", capabilities);
724487e
	for (i = 0; mtypes[i]; i++)
724487e
		if (strcasecmp(mtypes[i], capabilities) == 0)
724487e
			return cap_map[i];
724487e
	if ((i = strtol(capabilities, &endptr, 16)) <= 0xffff  &&  endptr[0] == 0)
724487e
		return i;
724487e
	fprintf(stderr, "Invalid media advertisement value '%s'.\n"
724487e
			"  Either pass a numeric value or one of the following names:\n",
724487e
			capabilities);
724487e
	for (i = 0; mtypes[i]; i++)
724487e
		fprintf(stderr, "   %-14s %3.3x\n", mtypes[i], cap_map[i]);
724487e
	return -1;
724487e
}
724487e
724487e
/* Trivial versions if we don't link against libmii.c */
724487e
static const char *media_names[] = {
724487e
	"10baseT", "10baseT-FD", "100baseTx", "100baseTx-FD", "100baseT4",
724487e
	"Flow-control", 0,
724487e
};
724487e
/* Various non-good bits in the command register. */
724487e
static const char *bmcr_bits[] = {
724487e
	"  Internal Collision-Test enabled!\n", "",		/* 0x0080,0x0100 */
724487e
	"  Restarted auto-negotiation in progress!\n",
724487e
	"  Transceiver isolated from the MII!\n",
724487e
	"  Transceiver powered down!\n", "", "",
724487e
	"  Transceiver in loopback mode!\n",
724487e
	"  Transceiver currently being reset!\n",
724487e
};
724487e
724487e
int show_basic_mii(long ioaddr, int phy_id)
724487e
{
724487e
	int mii_reg, i;
724487e
	u16 mii_val[32];
724487e
	u16 bmcr, bmsr, new_bmsr, nway_advert, lkpar;
724487e
724487e
	for (mii_reg = 0; mii_reg < 8; mii_reg++)
724487e
		mii_val[mii_reg] = mdio_read(ioaddr, phy_id, mii_reg);
724487e
	if ( ! verbose) {
724487e
		printf("Basic registers of MII PHY #%d: ", phy_id);
724487e
		for (mii_reg = 0; mii_reg < 8; mii_reg++)
724487e
			printf(" %4.4x", mii_val[mii_reg]);
724487e
		printf(".\n");
724487e
	}
724487e
724487e
	if (mii_val[0] == 0xffff  ||  mii_val[1] == 0x0000) {
724487e
		printf("  No MII transceiver present!.\n");
724487e
		if (! opt_f) {
724487e
			printf("  Use '--force' to view the information anyway.\n");
724487e
			return -1;
724487e
		}
724487e
	}
724487e
	/* Descriptive rename. */
724487e
	bmcr = mii_val[0];
724487e
	bmsr = mii_val[1];
724487e
	nway_advert = mii_val[4];
724487e
	lkpar = mii_val[5];
724487e
724487e
	if (lkpar & 0x4000) {
724487e
		int negotiated = nway_advert & lkpar & 0x3e0;
724487e
		int max_capability = 0;
724487e
		/* Scan for the highest negotiated capability, highest priority
724487e
		   (100baseTx-FDX) to lowest (10baseT-HDX). */
724487e
		int media_priority[] = {8, 9, 7, 6, 5}; 	/* media_names[i-5] */
724487e
		printf(" The autonegotiated capability is %4.4x.\n", negotiated);
724487e
		for (i = 0; media_priority[i]; i++)
724487e
			if (negotiated & (1 << media_priority[i])) {
724487e
				max_capability = media_priority[i];
724487e
				break;
724487e
			}
724487e
		if (max_capability)
724487e
			printf("The autonegotiated media type is %s.\n",
724487e
				   media_names[max_capability - 5]);
724487e
		else
724487e
			printf("No common media type was autonegotiated!\n"
724487e
				   "This is extremely unusual and typically indicates a "
724487e
				   "configuration error.\n" "Perhaps the advertised "
724487e
				   "capability set was intentionally limited.\n");
724487e
	}
724487e
	printf(" Basic mode control register 0x%4.4x:", bmcr);
724487e
	if (bmcr & 0x1000)
724487e
		printf(" Auto-negotiation enabled.\n");
724487e
	else
724487e
		printf(" Auto-negotiation disabled, with\n"
724487e
			   " Speed fixed at 10%s mbps, %s-duplex.\n",
724487e
			   bmcr & 0x2000 ? "0" : "",
724487e
			   bmcr & 0x0100 ? "full":"half");
724487e
	for (i = 0; i < 9; i++)
724487e
		if (bmcr & (0x0080<
724487e
			printf(bmcr_bits[i]);
724487e
724487e
	new_bmsr = mdio_read(ioaddr, phy_id, 1);
724487e
	if ((bmsr & 0x0016) == 0x0004)
724487e
		printf( " You have link beat, and everything is working OK.\n");
724487e
	else
724487e
		printf(" Basic mode status register 0x%4.4x ... %4.4x.\n"
724487e
			   "   Link status: %sestablished.\n",
724487e
			   bmsr, new_bmsr,
724487e
			   bmsr & 0x0004 ? "" :
724487e
			   (new_bmsr & 0x0004) ? "previously broken, but now re" : "not ");
724487e
	if (verbose) {
724487e
		printf("   This transceiver is capable of ");
724487e
		if (bmsr & 0xF800) {
724487e
			for (i = 15; i >= 11; i--)
724487e
				if (bmsr & (1<
724487e
					printf(" %s", media_names[i-11]);
724487e
		} else
724487e
			printf("<Warning! No media capabilities>");
724487e
		printf(".\n");
724487e
		printf("   %s to perform Auto-negotiation, negotiation %scomplete.\n",
724487e
			   bmsr & 0x0008 ? "Able" : "Unable",
724487e
			   bmsr & 0x0020 ? "" : "not ");
724487e
	}
724487e
724487e
	if (bmsr & 0x0010)
724487e
		printf(" Remote fault detected!\n");
724487e
	if (bmsr & 0x0002)
724487e
		printf("   *** Link Jabber! ***\n");
724487e
724487e
	if (lkpar & 0x4000) {
724487e
		printf(" Your link partner advertised %4.4x:",
724487e
			   lkpar);
724487e
		for (i = 5; i >= 0; i--)
724487e
			if (lkpar & (0x20<
724487e
				printf(" %s", media_names[i]);
724487e
		printf("%s.\n", lkpar & 0x0400 ? ", w/ 802.3X flow control" : "");
724487e
	} else if (lkpar & 0x00A0)
724487e
		printf(" Your link partner is generating %s link beat  (no"
724487e
			   " autonegotiation).\n",
724487e
			   lkpar & 0x0080 ? "100baseTx" : "10baseT");
724487e
	else if ( ! (bmcr & 0x1000))
724487e
		printf(" Link partner information is not exchanged when in"
724487e
			   " fixed speed mode.\n");
724487e
	else if ( ! (new_bmsr & 0x004))
724487e
							;	/* If no partner, do not report status. */
724487e
	else if (lkpar == 0x0001  ||  lkpar == 0x0000) {
724487e
		printf(" Your link partner does not do autonegotiation, and this "
724487e
			   "transceiver type\n  does not report the sensed link "
724487e
			   "speed.\n");
724487e
	} else
724487e
		printf(" Your link partner is strange, status %4.4x.\n", lkpar);
724487e
724487e
	printf("   End of basic transceiver information.\n\n");
724487e
	return 0;
724487e
}
724487e
724487e
static void monitor_status(long ioaddr, int phy_id)
724487e
{
724487e
	unsigned int baseline_1 = 0x55555555; 	/* Always show initial status. */
724487e
724487e
	while (1) {
724487e
		unsigned int new_1 = mdio_read(ioaddr, phy_id, 1);
724487e
		if (new_1 != baseline_1) {
724487e
			printf("%-12s 0x%4.4x 0x%4.4x\n",
724487e
				   new_1 & 0x04 ? (new_1==0xffff ? "unknown" : "up") :
724487e
				   new_1 & 0x20 ? "negotiating" : "down",
724487e
				   new_1, mdio_read(ioaddr, phy_id, 5));
724487e
			fflush(stdout);
724487e
			baseline_1 = new_1;
724487e
		}
724487e
		sleep(1);
724487e
	}
724487e
}
724487e
724487e
int  show_mii_details(long ioaddr, int phy_id)
724487e
{
724487e
	int mii_reg, mii_val;
724487e
	printf(" MII PHY #%d transceiver registers:", phy_id);
724487e
	for (mii_reg = 0; mii_reg < 32; mii_reg++) {
724487e
		mii_val = mdio_read(skfd, phy_id, mii_reg);
724487e
		printf("%s %4.4x", (mii_reg % 8) == 0 ? "\n  " : "",
724487e
			   mii_val);
724487e
	}
724487e
	printf("\nThis version of 'mii-diag' has not been linked with "
724487e
			"the libmii.c library.\n"
724487e
			"  That library provides extended transceiver status reports.\n");
724487e
	return 0;
724487e
}
724487e
724487e
void monitor_mii(long ioaddr, int phy_id)
724487e
{
724487e
	fprintf(stderr, "\nThis version of 'mii-diag' has not been linked with "
724487e
			"the libmii.c library \n"
724487e
			"  required for the media monitor option.\n");
724487e
}
724487e
724487e
724487e

724487e
/*
724487e
 * Local variables:
724487e
 *  version-control: t
724487e
 *  kept-new-versions: 5
724487e
 *  c-indent-level: 4
724487e
 *  c-basic-offset: 4
724487e
 *  tab-width: 4
724487e
 *  compile-command: "gcc -Wall -Wstrict-prototypes -O mii-diag.c -DLIBMII libmii.c -o mii-diag"
724487e
 *  simple-compile-command: "gcc mii-diag.c -o mii-diag"
724487e
 * End:
724487e
 */