Blame SOURCES/mii-diag.c

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