# HG changeset patch # User gthomas # Date 1061920440 0 # Node ID 0832585993c182ff9e8416e9150ea7e434bcec08 # Parent 2af5a454cc1f9fe1ae426b688eb1c57835e7feed New abstractions to handle device specifics diff --git a/packages/devs/eth/phy/current/ChangeLog b/packages/devs/eth/phy/current/ChangeLog --- a/packages/devs/eth/phy/current/ChangeLog +++ b/packages/devs/eth/phy/current/ChangeLog @@ -1,3 +1,13 @@ +2003-08-26 Gary Thomas + + * src/DP83847.c: + * src/AM79C874.c: New file(s) - driver(s) for PHY devices. + + * src/eth_phy.c: + * include/eth_phy_dev.h: + * include/eth_phy.h: + * cdl/phy_eth_drivers.cdl: Add device/chip specific drivers. + 2003-08-19 Gary Thomas * src/eth_phy.c: diff --git a/packages/devs/eth/phy/current/cdl/phy_eth_drivers.cdl b/packages/devs/eth/phy/current/cdl/phy_eth_drivers.cdl --- a/packages/devs/eth/phy/current/cdl/phy_eth_drivers.cdl +++ b/packages/devs/eth/phy/current/cdl/phy_eth_drivers.cdl @@ -59,4 +59,22 @@ cdl_package CYGPKG_DEVS_ETH_PHY { include_dir cyg/io compile eth_phy.c + + cdl_option CYGHWR_DEVS_ETH_PHY_DP83847 { + display "NSDP83847" + flavor bool + default_value 0 + compile -library=libextras.a DP83847.c + description " + Include support for National Semiconductor DP83847 DsPHYTER II" + } + + cdl_option CYGHWR_DEVS_ETH_PHY_AM79C874 { + display "AMD 79C874" + flavor bool + default_value 0 + compile -library=libextras.a AM79C874.c + description " + Include support for AMD 79C874 NetPHY" + } } diff --git a/packages/devs/eth/phy/current/include/eth_phy.h b/packages/devs/eth/phy/current/include/eth_phy.h --- a/packages/devs/eth/phy/current/include/eth_phy.h +++ b/packages/devs/eth/phy/current/include/eth_phy.h @@ -4,7 +4,7 @@ // // eth_phy.h // -// API for ethernet transciever (PHY) support +// User API for ethernet transciever (PHY) support // //========================================================================== //####ECOSGPLCOPYRIGHTBEGIN#### @@ -52,36 +52,48 @@ // //========================================================================== - -// Transceiver mode -#define PHY_BMCR 0x00 // Register number -#define PHY_BMCR_RESET 0x8000 -#define PHY_BMCR_LOOPBACK 0x4000 -#define PHY_BMCR_100MB 0x2000 -#define PHY_BMCR_AUTO_NEG 0x1000 -#define PHY_BMCR_POWER_DOWN 0x0800 -#define PHY_BMCR_ISOLATE 0x0400 -#define PHY_BMCR_RESTART 0x0200 -#define PHY_BMCR_FULL_DUPLEX 0x0100 -#define PHY_BMCR_COLL_TEST 0x0080 - -#define PHY_BMSR 0x01 // Status register -#define PHY_BMSR_AUTO_NEG 0x0020 -#define PHY_BMSR_LINK 0x0004 +#define PHY_BIT_LEVEL_ACCESS_TYPE 0 +#define PHY_REG_LEVEL_ACCESS_TYPE 1 // Physical device access - defined by hardware instance typedef struct { + int ops_type; // 0 => bit level, 1 => register level + bool init_done; void (*init)(void); - void (*set_data)(int); - int (*get_data)(void); - void (*set_clock)(int); - void (*set_dir)(int); + void (*reset)(void); + union { + struct { + void (*set_data)(int); + int (*get_data)(void); + void (*set_clock)(int); + void (*set_dir)(int); + } bit_level_ops; + struct { + void (*put_reg)(int reg, int unit, unsigned short data); + bool (*get_reg)(int reg, int unit, unsigned short *data); + } reg_level_ops; + } ops; + int phy_addr; + struct _eth_phy_dev_entry *dev; // Chip access functions } eth_phy_access_t; -#define ETH_PHY_ACCESS_FUNS(_l,_init,_set_data,_get_data,_set_clock,_set_dir) \ -static eth_phy_access_t _l = {_init, _set_data, _get_data, _set_clock, _set_dir} +#define ETH_PHY_BIT_LEVEL_ACCESS_FUNS(_l,_init,_reset,_set_data,_get_data,_set_clock,_set_dir) \ +static eth_phy_access_t _l = {PHY_BIT_LEVEL_ACCESS_TYPE, false, _init, _reset, \ + {.bit_level_ops = {_set_data, _get_data, _set_clock, _set_dir}}} + +#define ETH_PHY_REG_LEVEL_ACCESS_FUNS(_l,_init,_reset,_put_reg,_get_reg) \ +static eth_phy_access_t _l = {PHY_REG_LEVEL_ACCESS_TYPE, false, _init, _reset, \ + {.reg_level_ops = {_put_reg, _get_reg}}} -externC void _eth_phy_init(eth_phy_access_t *f); +#define ETH_PHY_STAT_LINK 0x0001 // Link up/down +#define ETH_PHY_STAT_100MB 0x0002 // Connection is 100Mb +#define ETH_PHY_STAT_FDX 0x0004 // Connection is full duplex + +externC bool _eth_phy_init(eth_phy_access_t *f); +externC void _eth_phy_reset(eth_phy_access_t *f); +externC int _eth_phy_state(eth_phy_access_t *f); +externC int _eth_phy_cfg(eth_phy_access_t *f, int mode); +// Internal routines externC void _eth_phy_write(eth_phy_access_t *f, int reg, int unit, unsigned short data); externC bool _eth_phy_read(eth_phy_access_t *f, int reg, int unit, unsigned short *val); diff --git a/packages/devs/eth/phy/current/include/eth_phy_dev.h b/packages/devs/eth/phy/current/include/eth_phy_dev.h new file mode 100644 --- /dev/null +++ b/packages/devs/eth/phy/current/include/eth_phy_dev.h @@ -0,0 +1,91 @@ +#ifndef CYGONCE_DEVS_ETH_PHY_DEV_H_ +#define CYGONCE_DEVS_ETH_PHY_DEV_H_ +//========================================================================== +// +// eth_phy_dev.h +// +// Device API for ethernet transciever (PHY) support +// +//========================================================================== +//####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2003 Gary Thomas +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with eCos; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +// +// As a special exception, if other files instantiate templates or use macros +// or inline functions from this file, or you compile this file and link it +// with other works to produce a work based on this file, this file does not +// by itself cause the resulting work to be covered by the GNU General Public +// License. However the source code for this file must still be made available +// in accordance with section (3) of the GNU General Public License. +// +// This exception does not invalidate any other reasons why a work based on +// this file might be covered by the GNU General Public License. +// +// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. +// at http://sources.redhat.com/ecos/ecos-license/ +// ------------------------------------------- +//####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): gthomas +// Contributors: gthomas +// Date: 2003-08-01 +// Purpose: +// Description: +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +// Transceiver mode +#define PHY_BMCR 0x00 // Register number +#define PHY_BMCR_RESET 0x8000 +#define PHY_BMCR_LOOPBACK 0x4000 +#define PHY_BMCR_100MB 0x2000 +#define PHY_BMCR_AUTO_NEG 0x1000 +#define PHY_BMCR_POWER_DOWN 0x0800 +#define PHY_BMCR_ISOLATE 0x0400 +#define PHY_BMCR_RESTART 0x0200 +#define PHY_BMCR_FULL_DUPLEX 0x0100 +#define PHY_BMCR_COLL_TEST 0x0080 + +#define PHY_BMSR 0x01 // Status register +#define PHY_BMSR_100T4 0x8000 +#define PHY_BMSR_100FDX 0x4000 +#define PHY_BMSR_100HDX 0x2000 +#define PHY_BMSR_10FDX 0x1000 +#define PHY_BMSR_10HDX 0x0800 +#define PHY_BMSR_AUTO_NEG 0x0020 +#define PHY_BMSR_LINK 0x0004 + +#define PHY_ID1 0x02 // Chip ID register (high 16 bits) +#define PHY_ID2 0x03 // Chip ID register (low 16 bits) + +struct _eth_phy_dev_entry { + char *name; + unsigned long id; + bool (*stat)(eth_phy_access_t *f, int *stat); +} CYG_HAL_TABLE_TYPE; + +#define _eth_phy_dev(_name_,_id_,_stat_) \ +struct _eth_phy_dev_entry _eth_phy_dev_##_id_ \ + CYG_HAL_TABLE_QUALIFIED_ENTRY(_eth_phy_devs,_id_) = \ + { _name_, _id_, _stat_ }; + +#endif // CYGONCE_DEVS_ETH_PHY_DEV_H_ +// ------------------------------------------------------------------------ diff --git a/packages/devs/eth/phy/current/src/AM79C874.c b/packages/devs/eth/phy/current/src/AM79C874.c new file mode 100644 --- /dev/null +++ b/packages/devs/eth/phy/current/src/AM79C874.c @@ -0,0 +1,101 @@ +//========================================================================== +// +// dev/AM79C874.c +// +// Ethernet transciever (PHY) support +// +//========================================================================== +//####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2003 Gary Thomas +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with eCos; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +// +// As a special exception, if other files instantiate templates or use macros +// or inline functions from this file, or you compile this file and link it +// with other works to produce a work based on this file, this file does not +// by itself cause the resulting work to be covered by the GNU General Public +// License. However the source code for this file must still be made available +// in accordance with section (3) of the GNU General Public License. +// +// This exception does not invalidate any other reasons why a work based on +// this file might be covered by the GNU General Public License. +// +// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. +// at http://sources.redhat.com/ecos/ecos-license/ +// ------------------------------------------- +//####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): gthomas +// Contributors: +// Date: 2003-08-01 +// Purpose: +// Description: Support for ethernet NS AM79C874 PHY +// +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +static bool am79c874_stat(eth_phy_access_t *f, int *state) +{ + unsigned short phy_state; + int tries; + + // Read negotiated state + if (_eth_phy_read(f, 0x1, f->phy_addr, &phy_state)) { + if ((phy_state & 0x20) == 0) { + diag_printf("... waiting for auto-negotiation"); + for (tries = 0; tries < 15; tries++) { + if (_eth_phy_read(f, 0x1, f->phy_addr, &phy_state)) { + if ((phy_state & 0x20) != 0) { + break; + } + } + CYGACC_CALL_IF_DELAY_US(1000000); // 1 second + diag_printf("."); + } + diag_printf("\n"); + } + if ((phy_state & 0x20) != 0) { + *state = 0; + if ((phy_state & 0x0004) != 0) *state |= ETH_PHY_STAT_LINK; + if (_eth_phy_read(f, 0x5, f->phy_addr, &phy_state)) { + // Partner negotiated parameters + if ((phy_state & 0x0100) != 0) *state |= ETH_PHY_STAT_100MB | ETH_PHY_STAT_FDX; + if ((phy_state & 0x0080) != 0) *state |= ETH_PHY_STAT_100MB; + if ((phy_state & 0x0040) != 0) *state |= ETH_PHY_STAT_FDX; + return true; + } + } + } + return false; +} + +_eth_phy_dev("AMD AM79C874", 0x0022561B, am79c874_stat) diff --git a/packages/devs/eth/phy/current/src/DP83847.c b/packages/devs/eth/phy/current/src/DP83847.c new file mode 100644 --- /dev/null +++ b/packages/devs/eth/phy/current/src/DP83847.c @@ -0,0 +1,97 @@ +//========================================================================== +// +// dev/DP83847.c +// +// Ethernet transciever (PHY) support +// +//========================================================================== +//####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2003 Gary Thomas +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with eCos; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +// +// As a special exception, if other files instantiate templates or use macros +// or inline functions from this file, or you compile this file and link it +// with other works to produce a work based on this file, this file does not +// by itself cause the resulting work to be covered by the GNU General Public +// License. However the source code for this file must still be made available +// in accordance with section (3) of the GNU General Public License. +// +// This exception does not invalidate any other reasons why a work based on +// this file might be covered by the GNU General Public License. +// +// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. +// at http://sources.redhat.com/ecos/ecos-license/ +// ------------------------------------------- +//####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): gthomas +// Contributors: +// Date: 2003-08-01 +// Purpose: +// Description: Support for ethernet NS DP83847 PHY +// +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +static bool dp83847_stat(eth_phy_access_t *f, int *state) +{ + unsigned short phy_state; + int tries; + + // Read negotiated state + if (_eth_phy_read(f, 0x10, f->phy_addr, &phy_state)) { + if ((phy_state & 0x10) == 0) { + diag_printf("... waiting for auto-negotiation"); + for (tries = 0; tries < 15; tries++) { + if (_eth_phy_read(f, 0x10, f->phy_addr, &phy_state)) { + if ((phy_state & 0x10) != 0) { + break; + } + } + CYGACC_CALL_IF_DELAY_US(1000000); // 1 second + diag_printf("."); + } + diag_printf("\n"); + } + if ((phy_state & 0x10) != 0) { + *state = 0; + if ((phy_state & 0x0001) != 0) *state |= ETH_PHY_STAT_LINK; + if ((phy_state & 0x0002) == 0) *state |= ETH_PHY_STAT_100MB; + if ((phy_state & 0x0004) != 0) *state |= ETH_PHY_STAT_FDX; + return true; + } + } + return false; +} + +_eth_phy_dev("National Semiconductor DP83847", 0x20005c30, dp83847_stat) diff --git a/packages/devs/eth/phy/current/src/eth_phy.c b/packages/devs/eth/phy/current/src/eth_phy.c --- a/packages/devs/eth/phy/current/src/eth_phy.c +++ b/packages/devs/eth/phy/current/src/eth_phy.c @@ -58,8 +58,15 @@ #include #include #include +#include #include +#include + +// Define table boundaries +CYG_HAL_TABLE_BEGIN( __ETH_PHY_TAB__, _eth_phy_devs ); +CYG_HAL_TABLE_END( __ETH_PHY_TAB_END__, _eth_phy_devs ); +extern struct _eth_phy_dev_entry __ETH_PHY_TAB__[], __ETH_PHY_TAB_END__; // MII interface #define MII_Start 0x40000000 @@ -71,7 +78,7 @@ #define MII_TA 0x00020000 // -// PHY unit access (via MII channel) +// PHY unit access (via MII channel, using bit-level operations) // static cyg_uint32 @@ -82,23 +89,23 @@ phy_cmd(eth_phy_access_t *f, cyg_uint32 bool is_read = ((cmd & MII_Cmd) == MII_Read); // Set both bits as output - (f->set_dir)(1); + (f->ops.bit_level_ops.set_dir)(1); // Preamble for (i = 0; i < 32; i++) { - (f->set_clock)(0); - (f->set_data)(1); + (f->ops.bit_level_ops.set_clock)(0); + (f->ops.bit_level_ops.set_data)(1); CYGACC_CALL_IF_DELAY_US(1); - (f->set_clock)(1); + (f->ops.bit_level_ops.set_clock)(1); CYGACC_CALL_IF_DELAY_US(1); } // Command/data for (i = 0, off = 31; i < (is_read ? 14 : 32); i++, --off) { - (f->set_clock)(0); - (f->set_data)((cmd >> off) & 0x00000001); + (f->ops.bit_level_ops.set_clock)(0); + (f->ops.bit_level_ops.set_data)((cmd >> off) & 0x00000001); CYGACC_CALL_IF_DELAY_US(1); - (f->set_clock)(1); + (f->ops.bit_level_ops.set_clock)(1); CYGACC_CALL_IF_DELAY_US(1); } @@ -108,49 +115,95 @@ phy_cmd(eth_phy_access_t *f, cyg_uint32 if (is_read) { retval >>= 16; - (f->set_clock)(0); - (f->set_dir)(0); + (f->ops.bit_level_ops.set_clock)(0); + (f->ops.bit_level_ops.set_dir)(0); CYGACC_CALL_IF_DELAY_US(1); - (f->set_clock)(1); + (f->ops.bit_level_ops.set_clock)(1); CYGACC_CALL_IF_DELAY_US(1); - (f->set_clock)(0); + (f->ops.bit_level_ops.set_clock)(0); CYGACC_CALL_IF_DELAY_US(1); for (i = 0, off = 15; i < 16; i++, off--) { - (f->set_clock)(1); + (f->ops.bit_level_ops.set_clock)(1); retval <<= 1; - retval |= (f->get_data)(); + retval |= (f->ops.bit_level_ops.get_data)(); CYGACC_CALL_IF_DELAY_US(1); - (f->set_clock)(0); + (f->ops.bit_level_ops.set_clock)(0); CYGACC_CALL_IF_DELAY_US(1); } } // Set both bits as output - (f->set_dir)(1); + (f->ops.bit_level_ops.set_dir)(1); // Postamble for (i = 0; i < 32; i++) { - (f->set_clock)(0); - (f->set_data)(1); + (f->ops.bit_level_ops.set_clock)(0); + (f->ops.bit_level_ops.set_data)(1); CYGACC_CALL_IF_DELAY_US(1); - (f->set_clock)(1); + (f->ops.bit_level_ops.set_clock)(1); CYGACC_CALL_IF_DELAY_US(1); } return retval; } -externC void +externC bool _eth_phy_init(eth_phy_access_t *f) { + int addr; + unsigned short state; + unsigned long id; + struct _eth_phy_dev_entry *dev; + + if (f->init_done) return true; + (f->init)(); + // Scan to determine PHY address + f->init_done = true; + for (addr = 0; addr < 0x20; addr++) { + if (_eth_phy_read(f, PHY_ID1, addr, &state)) { + id = state << 16; + if (_eth_phy_read(f, PHY_ID2, addr, &state)) { + id |= state; + f->phy_addr = addr; + for (dev = __ETH_PHY_TAB__; dev != &__ETH_PHY_TAB_END__; dev++) { + if (dev->id == id) { + diag_printf("PHY: %s\n", dev->name); + f->dev = dev; + return true; + } + } + diag_printf("Unsupported PHY device - id: %x\n", id); + break; // Can't handle this PHY + } + } + } + f->init_done = false; + return false; +} + +externC void +_eth_phy_reset(eth_phy_access_t *f) +{ + if (!f->init_done) { + diag_printf("PHY reset without init on PHY: %x\n", f); + return; + } (f->init)(); } externC void _eth_phy_write(eth_phy_access_t *f, int reg, int addr, unsigned short data) { - phy_cmd(f, MII_Start | MII_Write | MII_Phy(addr) | MII_Reg(reg) | MII_TA | data); + if (!f->init_done) { + diag_printf("PHY write without init on PHY: %x\n", f); + return; + } + if (f->ops_type == PHY_BIT_LEVEL_ACCESS_TYPE) { + phy_cmd(f, MII_Start | MII_Write | MII_Phy(addr) | MII_Reg(reg) | MII_TA | data); + } else { + (f->ops.reg_level_ops.put_reg)(reg, addr, data); + } } externC bool @@ -158,11 +211,79 @@ externC bool { cyg_uint32 ret; - ret = phy_cmd(f, MII_Start | MII_Read | MII_Phy(addr) | MII_Reg(reg) | MII_TA); - *val = ret; - return true; + if (!f->init_done) { + diag_printf("PHY read without init on PHY: %x\n", f); + return false; + } + if (f->ops_type == PHY_BIT_LEVEL_ACCESS_TYPE) { + ret = phy_cmd(f, MII_Start | MII_Read | MII_Phy(addr) | MII_Reg(reg) | MII_TA); + *val = ret; + return true; + } else { + return (f->ops.reg_level_ops.get_reg)(reg, addr, val); + } } -externC void _eth_phy_init(eth_phy_access_t *f); -externC void _eth_phy_write(eth_phy_access_t *f, int reg, int unit, unsigned short data); -externC bool _eth_phy_read(eth_phy_access_t *f, int reg, int unit, unsigned short *val); +externC int +_eth_phy_cfg(eth_phy_access_t *f, int mode) +{ + int phy_timeout = 5*1000; // Wait 5 seconds max for link to clear + bool phy_ok; + unsigned short reset_mode, phy_state; + int i; + + if (!f->init_done) { + diag_printf("PHY config without init on PHY: %x\n", f); + return; + } + + // Reset PHY (transceiver) + phy_ok = false; + _eth_phy_reset(f); + + _eth_phy_write(f, PHY_BMCR, f->phy_addr, PHY_BMCR_RESET); + for (i = 0; i < 5*100; i++) { + phy_ok = _eth_phy_read(f, PHY_BMCR, f->phy_addr, &phy_state); + diag_printf("PHY: %x\n", phy_state); + if (phy_ok && !(phy_state & PHY_BMCR_RESET)) break; + CYGACC_CALL_IF_DELAY_US(10000); // 10ms + } + if (!phy_ok || (phy_state & PHY_BMCR_RESET)) { + diag_printf("PPC405: Can't get PHY unit to soft reset: %x\n", phy_state); + return 0; + } + + reset_mode = PHY_BMCR_RESTART | PHY_BMCR_AUTO_NEG; + _eth_phy_write(f, PHY_BMCR, f->phy_addr, reset_mode); + while (phy_timeout-- >= 0) { + phy_ok = _eth_phy_read(f, PHY_BMSR, f->phy_addr, &phy_state); + if (phy_ok && (phy_state & PHY_BMSR_AUTO_NEG)) { + break; + } else { + CYGACC_CALL_IF_DELAY_US(10000); // 10ms + } + } + if (phy_timeout <= 0) { + diag_printf("** PPC405 Warning: PHY LINK UP failed: %04x\n", phy_state); + return 0; + } + + return _eth_phy_state(f); +} + +externC int +_eth_phy_state(eth_phy_access_t *f) +{ + int state = 0; + + if (!f->init_done) { + diag_printf("PHY state without init on PHY: %x\n", f); + return 0; + } + if ((f->dev->stat)(f, &state)) { + return state; + } else { + return 0; + } + return state; +}