mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2025-12-05 15:15:44 +00:00
2005-11-02 straumanatslacdotstanford.edu
* libnetworking/Makefile.am, libnetworking/preinstall.am: Added simple implementation of ethernet media ioctl SIOCSIFMEDIA/SIOCGIFMEDIA for mii compliant phys. * libnetworking/rtems/rtems_mii_ioctl.c, libnetworking/rtems/rtems_mii_ioctl.h, libnetworking/rtems/rtems_mii_ioctl_kern.c: New files.
This commit is contained in:
@@ -1,3 +1,12 @@
|
||||
2005-11-02 straumanatslacdotstanford.edu
|
||||
|
||||
* libnetworking/Makefile.am,
|
||||
libnetworking/preinstall.am: Added simple implementation of ethernet
|
||||
media ioctl SIOCSIFMEDIA/SIOCGIFMEDIA for mii compliant phys.
|
||||
* libnetworking/rtems/rtems_mii_ioctl.c,
|
||||
libnetworking/rtems/rtems_mii_ioctl.h,
|
||||
libnetworking/rtems/rtems_mii_ioctl_kern.c: New files.
|
||||
|
||||
2005-11-02 straumanatslacdotstanford.edu
|
||||
|
||||
* libi2c/Makefile.am, libi2c/Makefile.in, libi2c/libi2c.c,
|
||||
|
||||
129
cpukit/libnetworking/rtems/rtems_mii_ioctl.c
Normal file
129
cpukit/libnetworking/rtems/rtems_mii_ioctl.c
Normal file
@@ -0,0 +1,129 @@
|
||||
/* $Id$ */
|
||||
|
||||
/* Simple (default) implementation for SIOCGIFMEDIA/SIOCSIFMEDIA
|
||||
* to be used by ethernet drivers [from their ioctl].
|
||||
*
|
||||
* USERSPACE UTILITIES
|
||||
*
|
||||
* NOTE: This much simpler than the BSD ifmedia API
|
||||
*/
|
||||
|
||||
/* Author: Till Straumann, <straumanatslacdotstandorddotedu>, 2005 */
|
||||
|
||||
#include <rtems.h>
|
||||
|
||||
#undef _KERNEL
|
||||
#undef KERNEL
|
||||
|
||||
#include <rtems/rtems_mii_ioctl.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
static struct ifmedia_description shared_media_strings[] =
|
||||
IFM_SUBTYPE_SHARED_DESCRIPTIONS;
|
||||
static struct ifmedia_description ethern_media_strings[] =
|
||||
IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
|
||||
static struct ifmedia_description eth_al_media_strings[] =
|
||||
IFM_SUBTYPE_ETHERNET_ALIASES;
|
||||
|
||||
static const char *
|
||||
find_desc (int tag, struct ifmedia_description *list)
|
||||
{
|
||||
while (list->ifmt_string && tag != list->ifmt_word)
|
||||
list++;
|
||||
return list->ifmt_string;
|
||||
}
|
||||
|
||||
#define WHATPRINT(buf,sz,fmt...) \
|
||||
( (sz) > 0 ? snprintf((buf),(sz),fmt) : fprintf((buf) ? (FILE*)(buf) : stdout, fmt) )
|
||||
|
||||
int
|
||||
rtems_ifmedia2str (int media, char *buf, int bufsz)
|
||||
{
|
||||
const char *mdesc;
|
||||
const char *dupdesc = 0;
|
||||
|
||||
/* only ethernet supported, so far */
|
||||
if (IFM_ETHER != IFM_TYPE (media))
|
||||
return -1;
|
||||
|
||||
if (!(mdesc = find_desc (IFM_SUBTYPE (media), shared_media_strings)))
|
||||
mdesc = find_desc (IFM_SUBTYPE (media), ethern_media_strings);
|
||||
|
||||
if (!mdesc)
|
||||
return -1;
|
||||
|
||||
if (IFM_NONE != IFM_SUBTYPE (media))
|
||||
dupdesc = IFM_FDX & media ? " full-duplex" : " half-duplex";
|
||||
|
||||
return WHATPRINT (buf, bufsz,
|
||||
"Ethernet [phy instance: %i]: (link %s, autoneg %s) -- media: %s%s",
|
||||
IFM_INST (media),
|
||||
IFM_LINK_OK & media ? "ok" : "down",
|
||||
IFM_ANEG_DIS & media ? "off" : "on",
|
||||
mdesc, dupdesc ? dupdesc : "");
|
||||
}
|
||||
|
||||
static int
|
||||
find_tag (const char *desc, struct ifmedia_description *list)
|
||||
{
|
||||
while (list->ifmt_string) {
|
||||
if (strstr (desc, list->ifmt_string))
|
||||
return list->ifmt_word;
|
||||
list++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* convert a string to a media word
|
||||
* RETURNS: 0 on failure; valid results have always at least IFM_ETHER set
|
||||
*/
|
||||
int
|
||||
rtems_str2ifmedia (const char *str, int phy)
|
||||
{
|
||||
int sub, opt = 0;
|
||||
char *chpt;
|
||||
|
||||
if (!strncmp (str, "auto", 4)) {
|
||||
sub = IFM_AUTO;
|
||||
} else if ((sub = find_tag (str, ethern_media_strings)) < 0) {
|
||||
if ((sub = find_tag (str, eth_al_media_strings)) < 0) {
|
||||
/* allow more */
|
||||
|
||||
/* if no number, 0 is returned which will not pass the test */
|
||||
switch (strtol (str, &chpt, 10)) {
|
||||
case 10:
|
||||
sub = IFM_10_T;
|
||||
break;
|
||||
case 100:
|
||||
sub = IFM_100_TX;
|
||||
break;
|
||||
case 1000:
|
||||
sub = IFM_1000_T;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* need 'b' or 'base' */
|
||||
if ('b' != *chpt++)
|
||||
return 0;
|
||||
if (!strncmp (chpt, "ase", 3))
|
||||
chpt += 3;
|
||||
if (toupper (*chpt++) != 'T')
|
||||
return 0;
|
||||
if (IFM_100_TX == sub && toupper (*chpt++) != 'X')
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (strstr (str, "full") || strstr (str, "FDX") || strstr (str, "fdx"))
|
||||
opt |= IFM_FDX;
|
||||
|
||||
return IFM_MAKEWORD (IFM_ETHER, sub, opt, phy);
|
||||
}
|
||||
99
cpukit/libnetworking/rtems/rtems_mii_ioctl.h
Normal file
99
cpukit/libnetworking/rtems/rtems_mii_ioctl.h
Normal file
@@ -0,0 +1,99 @@
|
||||
#ifndef RTEMS_MII_IOCTL_H
|
||||
#define RTEMS_MII_IOCTL_H
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
/* Simple (default) implementation for SIOCGIFMEDIA/SIOCSIFMEDIA
|
||||
* to be used by ethernet drivers [from their ioctl].
|
||||
*
|
||||
* NOTE: This much simpler than the BSD ifmedia API
|
||||
*/
|
||||
|
||||
/* Author: Till Straumann, <straumanatslacdotstandorddotedu>, 2005 */
|
||||
|
||||
/* These should be moved out of <libchip>... */
|
||||
#include <libchip/mii.h> /* MII register definitions */
|
||||
#include <libchip/if_media.h> /* media word definitions; rest of API (ifmedia) unused! */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(_KERNEL) || defined(KERNEL) || defined(__KERNEL) || defined(__KERNEL__)
|
||||
/* mdio routines to be provided by driver */
|
||||
|
||||
/* read mii register 'reg' at 'phy' (-1 meaning any/currently active)
|
||||
* RETURNS 0 on success, -1 otherwise (e.g., illegal phy)
|
||||
*/
|
||||
typedef int (*rtems_mdio_read_func) (int phy, void *uarg, unsigned reg,
|
||||
unsigned32 * pval);
|
||||
|
||||
/* write mii register 'reg' at 'phy' (-1 meaning any/currently active)
|
||||
* RETURNS 0 on success, -1 otherwise (e.g., illegal phy)
|
||||
*/
|
||||
typedef int (*rtems_mdio_write_func) (int phy, void *uarg, unsigned reg,
|
||||
unsigned32 val);
|
||||
|
||||
/* Values to this must be provided by the driver */
|
||||
struct rtems_mdio_info
|
||||
{
|
||||
rtems_mdio_read_func mdio_r;
|
||||
rtems_mdio_write_func mdio_w;
|
||||
unsigned has_gmii:1; /* supports gigabit */
|
||||
};
|
||||
|
||||
/* Implement SIOCSIFMEDIA/SIOCGIFMEDIA; get/set the current media word. Note
|
||||
* that this does NOT implement the full BSD 'ifmedia' API; also, it only
|
||||
* implements IFM_ETHER...
|
||||
*
|
||||
* INPUT:
|
||||
* SIOCGIFMEDIA: the media word must set the phy instance (-1 for 'any')
|
||||
*
|
||||
*/
|
||||
int
|
||||
rtems_mii_ioctl (struct rtems_mdio_info *info, void *uarg, int cmd,
|
||||
int *media);
|
||||
|
||||
#endif
|
||||
|
||||
/* The driver flags have the following meaning (SIOCGIFMEDIA only):
|
||||
*/
|
||||
#define IFM_LINK_OK IFM_FLAG0
|
||||
#define IFM_ANEG_DIS IFM_FLAG1 /* autoneg. disabled; media forced */
|
||||
|
||||
/* convert a media word to a string;
|
||||
*
|
||||
* RETURNS: number of characters written to 'buf'
|
||||
*
|
||||
* INPUT: if 'bufsz' is set to IFMEDIA2STR_PRINT_TO_FILE, 'buf' can be a FILE pointer
|
||||
* where the info is printed insted. This can be NULL in which
|
||||
* case 'stdout' is used.
|
||||
*/
|
||||
|
||||
#define IFMEDIA2STR_PRINT_TO_FILE 0
|
||||
|
||||
int rtems_ifmedia2str (int media, char *buf, int bufsz);
|
||||
|
||||
/* convert a string to a media word
|
||||
* RETURNS: 0 on failure (unrecognized or invalid mode);
|
||||
* valid results have always at least IFM_ETHER set.
|
||||
*
|
||||
* In addition to IFM_SUBTYPE_ETHERNET_DESCRIPTIONS and IFM_SUBTYPE_ETHERNET_ALIASES,
|
||||
* the strings
|
||||
*
|
||||
* '10' [ '0' [ '0' ]] 'b' [ 'ase' ] ( 't' | 'T' ) (* if 100bT [ 'x' | 'X' ] is required here *)
|
||||
*
|
||||
* are recognized (e.g., 10bT, 100bTX)
|
||||
*
|
||||
* if any of the strings 'full' or 'FDX' or 'fdx' is present, a full-duplex mode
|
||||
* is selected (half-duplex otherwise).
|
||||
* e.g., '100bTx-full'
|
||||
*/
|
||||
|
||||
int rtems_str2ifmedia (const char *str, int phy);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
193
cpukit/libnetworking/rtems/rtems_mii_ioctl_kern.c
Normal file
193
cpukit/libnetworking/rtems/rtems_mii_ioctl_kern.c
Normal file
@@ -0,0 +1,193 @@
|
||||
/* $Id$ */
|
||||
|
||||
/* Simple (default) implementation for SIOCGIFMEDIA/SIOCSIFMEDIA
|
||||
* to be used by ethernet drivers [from their ioctl].
|
||||
*
|
||||
* KERNEL PART (support for drivers)
|
||||
*
|
||||
* NOTE: This much simpler than the BSD ifmedia API
|
||||
*/
|
||||
|
||||
/* Author: Till Straumann, <straumanatslacdotstandorddotedu>, 2005 */
|
||||
|
||||
/* include first to avoid 'malloc' clash with rtems_bsdnet_malloc() hack */
|
||||
|
||||
#include <rtems.h>
|
||||
#include <rtems/rtems_bsdnet.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#ifndef __KERNEL__
|
||||
#define __KERNEL__
|
||||
#endif
|
||||
|
||||
#include <rtems/rtems_mii_ioctl.h>
|
||||
|
||||
#include <sys/errno.h>
|
||||
|
||||
|
||||
#define DEBUG
|
||||
|
||||
|
||||
#ifndef MII_1000TCR
|
||||
#define MII_1000TCR MII_100T2CR
|
||||
#endif
|
||||
|
||||
#ifndef MII_1000TSR
|
||||
#define MII_1000TSR MII_100T2SR
|
||||
#endif
|
||||
|
||||
int
|
||||
rtems_mii_ioctl (struct rtems_mdio_info *info, void *uarg, int cmd,
|
||||
int *media)
|
||||
{
|
||||
unsigned32 bmcr, bmsr, bmcr2 = 0, bmsr2 = 0, anar, lpar;
|
||||
int phy = IFM_INST (*media);
|
||||
unsigned tmp;
|
||||
int subtype = 0, options = 0;
|
||||
|
||||
switch (cmd) {
|
||||
default:
|
||||
return EINVAL;
|
||||
|
||||
#ifdef DEBUG
|
||||
case 0:
|
||||
#endif
|
||||
case SIOCGIFMEDIA:
|
||||
if (info->mdio_r (phy, uarg, MII_BMCR, &bmcr))
|
||||
return EINVAL;
|
||||
if (info->mdio_r (phy, uarg, MII_BMSR, &bmsr))
|
||||
return EINVAL;
|
||||
if (info->has_gmii) {
|
||||
if (info->mdio_r (phy, uarg, MII_1000TCR, &bmcr2))
|
||||
return EINVAL;
|
||||
if (info->mdio_r (phy, uarg, MII_1000TSR, &bmsr2))
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* link status */
|
||||
if (BMSR_LINK & bmsr)
|
||||
options |= IFM_LINK_OK;
|
||||
|
||||
/* do we have autonegotiation disabled ? */
|
||||
if (!(BMCR_AUTOEN & bmcr)) {
|
||||
options |= IFM_ANEG_DIS;
|
||||
|
||||
/* duplex is enforced */
|
||||
options |= BMCR_FDX & bmcr ? IFM_FDX : IFM_HDX;
|
||||
|
||||
/* determine speed */
|
||||
switch (BMCR_SPEED (bmcr)) {
|
||||
case BMCR_S10:
|
||||
subtype = IFM_10_T;
|
||||
break;
|
||||
case BMCR_S100:
|
||||
subtype = IFM_100_TX;
|
||||
break;
|
||||
case BMCR_S1000:
|
||||
subtype = IFM_1000_T;
|
||||
break;
|
||||
default:
|
||||
return ENOTSUP; /* ?? */
|
||||
}
|
||||
} else if (!(BMSR_LINK & bmsr) || !(BMSR_ACOMP & bmsr)) {
|
||||
subtype = IFM_NONE;
|
||||
} else {
|
||||
/* everything ok */
|
||||
|
||||
tmp = ((bmcr2 >> 2) & bmsr2) & (GTSR_LP_1000THDX | GTSR_LP_1000TFDX);
|
||||
if (tmp) {
|
||||
if (GTSR_LP_1000TFDX & tmp)
|
||||
options |= IFM_FDX;
|
||||
subtype = IFM_1000_T;
|
||||
} else {
|
||||
if (info->mdio_r (phy, uarg, MII_ANAR, &anar))
|
||||
return EINVAL;
|
||||
if (info->mdio_r (phy, uarg, MII_ANLPAR, &lpar))
|
||||
return EINVAL;
|
||||
if (ANLPAR_ACK & lpar) {
|
||||
/* this is a negotiated link; otherwise we merely detect the partner's ability */
|
||||
}
|
||||
tmp = anar & lpar;
|
||||
if (ANLPAR_TX_FD & tmp) {
|
||||
options |= IFM_FDX;
|
||||
subtype = IFM_100_TX;
|
||||
} else if (ANLPAR_T4 & tmp) {
|
||||
subtype = IFM_100_T4;
|
||||
} else if (ANLPAR_TX & tmp) {
|
||||
subtype = IFM_100_TX;
|
||||
} else if (ANLPAR_10_FD & tmp) {
|
||||
options |= IFM_FDX;
|
||||
subtype = IFM_10_T;
|
||||
} else {
|
||||
subtype = IFM_10_T;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*media = IFM_MAKEWORD (IFM_ETHER, subtype, options, phy);
|
||||
|
||||
break;
|
||||
|
||||
#ifdef DEBUG
|
||||
case 1:
|
||||
#endif
|
||||
case SIOCSIFMEDIA:
|
||||
if (IFM_ETHER != IFM_TYPE (*media))
|
||||
return EINVAL;
|
||||
|
||||
if (info->mdio_r (phy, uarg, MII_BMSR, &bmsr))
|
||||
return EINVAL;
|
||||
|
||||
tmp = (IFM_FDX & *media);
|
||||
|
||||
switch (IFM_SUBTYPE (*media)) {
|
||||
default:
|
||||
return ENOTSUP;
|
||||
|
||||
case IFM_AUTO:
|
||||
bmcr = BMCR_AUTOEN | BMCR_STARTNEG;
|
||||
tmp = 0;
|
||||
break;
|
||||
|
||||
case IFM_1000_T:
|
||||
if (!info->has_gmii)
|
||||
return ENOTSUP;
|
||||
|
||||
if (info->mdio_r (phy, uarg, MII_EXTSR, &bmsr2))
|
||||
return EINVAL;
|
||||
|
||||
if (!(bmsr2 & (tmp ? EXTSR_1000TFDX : EXTSR_1000THDX)))
|
||||
return EOPNOTSUPP;
|
||||
bmcr = BMCR_S1000;
|
||||
break;
|
||||
|
||||
case IFM_100_TX:
|
||||
if (!(bmsr & (tmp ? BMSR_100TXFDX : BMSR_100TXHDX)))
|
||||
return EOPNOTSUPP;
|
||||
bmcr = BMCR_S100;
|
||||
break;
|
||||
|
||||
case IFM_10_T:
|
||||
if (!(bmsr & (tmp ? BMSR_10TFDX : BMSR_10THDX)))
|
||||
return EOPNOTSUPP;
|
||||
bmcr = BMCR_S10;
|
||||
break;
|
||||
}
|
||||
|
||||
if (tmp)
|
||||
bmcr |= BMCR_FDX;
|
||||
|
||||
if (info->mdio_w (phy, uarg, MII_BMCR, bmcr))
|
||||
return EINVAL;
|
||||
|
||||
/* TODO: should we adapt advertised capabilites ? */
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user