jpopelka / rpms / net-tools

Forked from rpms/net-tools 4 years ago
Clone

Blame SOURCES/mii-diag.c

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