diff options
-rw-r--r-- | sys/conf/files | 4 | ||||
-rw-r--r-- | sys/conf/kmod.mk | 2 | ||||
-rw-r--r-- | sys/dev/etherswitch/mdio.c | 117 | ||||
-rw-r--r-- | sys/dev/etherswitch/mdio.h | 35 | ||||
-rw-r--r-- | sys/dev/etherswitch/mdio_if.m | 24 | ||||
-rw-r--r-- | sys/dev/etherswitch/miiproxy.c | 444 | ||||
-rw-r--r-- | sys/dev/etherswitch/miiproxy.h | 37 |
7 files changed, 662 insertions, 1 deletions
diff --git a/sys/conf/files b/sys/conf/files index 49765bf..b1495ce 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -3683,3 +3683,7 @@ dev/xen/netback/netback.c optional xen | xenhvm dev/xen/netfront/netfront.c optional xen | xenhvm dev/xen/xenpci/xenpci.c optional xenpci dev/xen/xenpci/evtchn.c optional xenpci + +dev/etherswitch/mdio_if.m optional miiproxy +dev/etherswitch/mdio.c optional miiproxy +dev/etherswitch/miiproxy.c optional miiproxy diff --git a/sys/conf/kmod.mk b/sys/conf/kmod.mk index 929cec6..d2cf75f 100644 --- a/sys/conf/kmod.mk +++ b/sys/conf/kmod.mk @@ -354,7 +354,7 @@ MFILES?= dev/acpica/acpi_if.m dev/acpi_support/acpi_wmi_if.m \ kern/bus_if.m kern/clock_if.m \ kern/cpufreq_if.m kern/device_if.m kern/serdev_if.m \ libkern/iconv_converter_if.m opencrypto/cryptodev_if.m \ - pc98/pc98/canbus_if.m + pc98/pc98/canbus_if.m dev/etherswitch/mdio_if.m .for _srcsrc in ${MFILES} .for _ext in c h diff --git a/sys/dev/etherswitch/mdio.c b/sys/dev/etherswitch/mdio.c new file mode 100644 index 0000000..1d1d370 --- /dev/null +++ b/sys/dev/etherswitch/mdio.c @@ -0,0 +1,117 @@ +/*- + * Copyright (c) 2011-2012 Stefan Bethke. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <sys/param.h> +#include <sys/bus.h> +#include <sys/systm.h> + +#include <dev/etherswitch/mdio.h> + +#include "mdio_if.h" + +static void +mdio_identify(driver_t *driver, device_t parent) +{ + + if (device_find_child(parent, mdio_driver.name, -1) == NULL) + BUS_ADD_CHILD(parent, 0, mdio_driver.name, -1); +} + +static int +mdio_probe(device_t dev) +{ + + device_set_desc(dev, "MDIO"); + + return (BUS_PROBE_SPECIFIC); +} + +static int +mdio_attach(device_t dev) +{ + + bus_generic_probe(dev); + bus_enumerate_hinted_children(dev); + return (bus_generic_attach(dev)); +} + +static int +mdio_detach(device_t dev) +{ + + bus_generic_detach(dev); + return (0); +} + +static int +mdio_readreg(device_t dev, int phy, int reg) +{ + + return (MDIO_READREG(device_get_parent(dev), phy, reg)); +} + +static int +mdio_writereg(device_t dev, int phy, int reg, int val) +{ + + return (MDIO_WRITEREG(device_get_parent(dev), phy, reg, val)); +} + +static void +mdio_hinted_child(device_t dev, const char *name, int unit) +{ + + device_add_child(dev, name, unit); +} + +static device_method_t mdio_methods[] = { + /* device interface */ + DEVMETHOD(device_identify, mdio_identify), + DEVMETHOD(device_probe, mdio_probe), + DEVMETHOD(device_attach, mdio_attach), + DEVMETHOD(device_detach, mdio_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + + /* bus interface */ + DEVMETHOD(bus_add_child, device_add_child_ordered), + DEVMETHOD(bus_hinted_child, mdio_hinted_child), + + /* MDIO access */ + DEVMETHOD(mdio_readreg, mdio_readreg), + DEVMETHOD(mdio_writereg, mdio_writereg), + + DEVMETHOD_END +}; + +driver_t mdio_driver = { + "mdio", + mdio_methods, + 0 +}; + +devclass_t mdio_devclass; diff --git a/sys/dev/etherswitch/mdio.h b/sys/dev/etherswitch/mdio.h new file mode 100644 index 0000000..82578e0 --- /dev/null +++ b/sys/dev/etherswitch/mdio.h @@ -0,0 +1,35 @@ +/*- + * Copyright (c) 2011-2012 Stefan Bethke. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef __DEV_ETHERSWITCH_MDIO_H__ +#define __DEV_ETHERSWITCH_MDIO_H__ + +extern driver_t mdio_driver; +extern devclass_t mdio_devclass; + +#endif /* __DEV_ETHERSWITCH_MDIO_H__ */ diff --git a/sys/dev/etherswitch/mdio_if.m b/sys/dev/etherswitch/mdio_if.m new file mode 100644 index 0000000..9aedd92 --- /dev/null +++ b/sys/dev/etherswitch/mdio_if.m @@ -0,0 +1,24 @@ +# $FreeBSD$ + +#include <sys/bus.h> + +INTERFACE mdio; + +# +# Read register from device on MDIO bus +# +METHOD int readreg { + device_t dev; + int phy; + int reg; +}; + +# +# Write register to device on MDIO bus +# +METHOD int writereg { + device_t dev; + int phy; + int reg; + int val; +}; diff --git a/sys/dev/etherswitch/miiproxy.c b/sys/dev/etherswitch/miiproxy.c new file mode 100644 index 0000000..fe1685d --- /dev/null +++ b/sys/dev/etherswitch/miiproxy.c @@ -0,0 +1,444 @@ +/*- + * Copyright (c) 2011-2012 Stefan Bethke. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <sys/param.h> +#include <sys/bus.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/systm.h> + +#include <net/if.h> +#include <net/if_arp.h> +#include <net/ethernet.h> +#include <net/if_dl.h> +#include <net/if_media.h> +#include <net/if_types.h> + +#include <dev/etherswitch/miiproxy.h> +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> + +#include "mdio_if.h" +#include "miibus_if.h" + + +MALLOC_DECLARE(M_MIIPROXY); +MALLOC_DEFINE(M_MIIPROXY, "miiproxy", "miiproxy data structures"); + +driver_t miiproxy_driver; +driver_t mdioproxy_driver; + +struct miiproxy_softc { + device_t parent; + device_t proxy; + device_t mdio; +}; + +struct mdioproxy_softc { +}; + +/* + * The rendevous data structures and functions allow two device endpoints to + * match up, so that the proxy endpoint can be associated with a target + * endpoint. The proxy has to know the device name of the target that it + * wants to associate with, for example through a hint. The rendevous code + * makes no assumptions about the devices that want to meet. + */ +struct rendevous_entry; + +enum rendevous_op { + RENDEVOUS_ATTACH, + RENDEVOUS_DETACH +}; + +typedef int (*rendevous_callback_t)(enum rendevous_op, + struct rendevous_entry *); + +static SLIST_HEAD(rendevoushead, rendevous_entry) rendevoushead = + SLIST_HEAD_INITIALIZER(rendevoushead); + +struct rendevous_endpoint { + device_t device; + const char *name; + rendevous_callback_t callback; +}; + +struct rendevous_entry { + SLIST_ENTRY(rendevous_entry) entries; + struct rendevous_endpoint proxy; + struct rendevous_endpoint target; +}; + +/* + * Call the callback routines for both the proxy and the target. If either + * returns an error, undo the attachment. + */ +static int +rendevous_attach(struct rendevous_entry *e, struct rendevous_endpoint *ep) +{ + int error; + + error = e->proxy.callback(RENDEVOUS_ATTACH, e); + if (error == 0) { + error = e->target.callback(RENDEVOUS_ATTACH, e); + if (error != 0) { + e->proxy.callback(RENDEVOUS_DETACH, e); + ep->device = NULL; + ep->callback = NULL; + } + } + return (error); +} + +/* + * Create an entry for the proxy in the rendevous list. The name parameter + * indicates the name of the device that is the target endpoint for this + * rendevous. The callback will be invoked as soon as the target is + * registered: either immediately if the target registered itself earlier, + * or once the target registers. Returns ENXIO if the target has not yet + * registered. + */ +static int +rendevous_register_proxy(device_t dev, const char *name, + rendevous_callback_t callback) +{ + struct rendevous_entry *e; + + KASSERT(callback != NULL, ("callback must be set")); + SLIST_FOREACH(e, &rendevoushead, entries) { + if (strcmp(name, e->target.name) == 0) { + /* the target is already attached */ + e->proxy.name = device_get_nameunit(dev); + e->proxy.device = dev; + e->proxy.callback = callback; + return (rendevous_attach(e, &e->proxy)); + } + } + e = malloc(sizeof(*e), M_MIIPROXY, M_WAITOK | M_ZERO); + e->proxy.name = device_get_nameunit(dev); + e->proxy.device = dev; + e->proxy.callback = callback; + e->target.name = name; + SLIST_INSERT_HEAD(&rendevoushead, e, entries); + return (ENXIO); +} + +/* + * Create an entry in the rendevous list for the target. + * Returns ENXIO if the proxy has not yet registered. + */ +static int +rendevous_register_target(device_t dev, rendevous_callback_t callback) +{ + struct rendevous_entry *e; + const char *name; + + KASSERT(callback != NULL, ("callback must be set")); + name = device_get_nameunit(dev); + SLIST_FOREACH(e, &rendevoushead, entries) { + if (strcmp(name, e->target.name) == 0) { + e->target.device = dev; + e->target.callback = callback; + return (rendevous_attach(e, &e->target)); + } + } + e = malloc(sizeof(*e), M_MIIPROXY, M_WAITOK | M_ZERO); + e->target.name = name; + e->target.device = dev; + e->target.callback = callback; + SLIST_INSERT_HEAD(&rendevoushead, e, entries); + return (ENXIO); +} + +/* + * Remove the registration for the proxy. + */ +static int +rendevous_unregister_proxy(device_t dev) +{ + struct rendevous_entry *e; + int error = 0; + + SLIST_FOREACH(e, &rendevoushead, entries) { + if (e->proxy.device == dev) { + if (e->target.device == NULL) { + SLIST_REMOVE(&rendevoushead, e, rendevous_entry, entries); + free(e, M_MIIPROXY); + return (0); + } else { + e->proxy.callback(RENDEVOUS_DETACH, e); + e->target.callback(RENDEVOUS_DETACH, e); + } + e->proxy.device = NULL; + e->proxy.callback = NULL; + return (error); + } + } + return (ENOENT); +} + +/* + * Remove the registration for the target. + */ +static int +rendevous_unregister_target(device_t dev) +{ + struct rendevous_entry *e; + int error = 0; + + SLIST_FOREACH(e, &rendevoushead, entries) { + if (e->target.device == dev) { + if (e->proxy.device == NULL) { + SLIST_REMOVE(&rendevoushead, e, rendevous_entry, entries); + free(e, M_MIIPROXY); + return (0); + } else { + e->proxy.callback(RENDEVOUS_DETACH, e); + e->target.callback(RENDEVOUS_DETACH, e); + } + e->target.device = NULL; + e->target.callback = NULL; + return (error); + } + } + return (ENOENT); +} + +/* + * Functions of the proxy that is interposed between the ethernet interface + * driver and the miibus device. + */ + +static int +miiproxy_rendevous_callback(enum rendevous_op op, struct rendevous_entry *rendevous) +{ + struct miiproxy_softc *sc = device_get_softc(rendevous->proxy.device); + + switch (op) { + case RENDEVOUS_ATTACH: + sc->mdio = device_get_parent(rendevous->target.device); + break; + case RENDEVOUS_DETACH: + sc->mdio = NULL; + break; + } + return (0); +} + +static int +miiproxy_probe(device_t dev) +{ + device_set_desc(dev, "MII/MDIO proxy, MII side"); + + return (BUS_PROBE_SPECIFIC); +} + +static int +miiproxy_attach(device_t dev) +{ + + /* + * The ethernet interface needs to call mii_attach_proxy() to pass + * the relevant parameters for rendevous with the MDIO target. + */ + return (bus_generic_attach(dev)); +} + +static int +miiproxy_detach(device_t dev) +{ + + rendevous_unregister_proxy(dev); + bus_generic_detach(dev); + return (0); +} + +static int +miiproxy_readreg(device_t dev, int phy, int reg) +{ + struct miiproxy_softc *sc = device_get_softc(dev); + + if (sc->mdio != NULL) + return (MDIO_READREG(sc->mdio, phy, reg)); + return (-1); +} + +static int +miiproxy_writereg(device_t dev, int phy, int reg, int val) +{ + struct miiproxy_softc *sc = device_get_softc(dev); + + if (sc->mdio != NULL) + return (MDIO_WRITEREG(sc->mdio, phy, reg, val)); + return (-1); +} + +static void +miiproxy_statchg(device_t dev) +{ + + MIIBUS_STATCHG(device_get_parent(dev)); +} + +static void +miiproxy_linkchg(device_t dev) +{ + + MIIBUS_LINKCHG(device_get_parent(dev)); +} + +static void +miiproxy_mediainit(device_t dev) +{ + + MIIBUS_MEDIAINIT(device_get_parent(dev)); +} + +/* + * Functions for the MDIO target device driver. + */ +static int +mdioproxy_rendevous_callback(enum rendevous_op op, struct rendevous_entry *rendevous) +{ + return (0); +} + +static void +mdioproxy_identify(driver_t *driver, device_t parent) +{ + device_t child; + + if (device_find_child(parent, driver->name, -1) == NULL) { + child = BUS_ADD_CHILD(parent, 0, driver->name, -1); + } +} + +static int +mdioproxy_probe(device_t dev) +{ + device_set_desc(dev, "MII/MDIO proxy, MDIO side"); + + return (BUS_PROBE_SPECIFIC); +} + +static int +mdioproxy_attach(device_t dev) +{ + + rendevous_register_target(dev, mdioproxy_rendevous_callback); + return (bus_generic_attach(dev)); +} + +static int +mdioproxy_detach(device_t dev) +{ + + rendevous_unregister_target(dev); + bus_generic_detach(dev); + return (0); +} + +/* + * Attach this proxy in place of miibus. The target MDIO must be attached + * already. Returns NULL on error. + */ +device_t +mii_attach_proxy(device_t dev) +{ + struct miiproxy_softc *sc; + int error; + const char *name; + device_t miiproxy; + + if (resource_string_value(device_get_name(dev), + device_get_unit(dev), "mdio", &name) != 0) { + if (bootverbose) + printf("mii_attach_proxy: not attaching, no mdio" + " device hint for %s\n", device_get_nameunit(dev)); + return (NULL); + } + + miiproxy = device_add_child(dev, miiproxy_driver.name, -1); + error = bus_generic_attach(dev); + if (error != 0) { + device_printf(dev, "can't attach miiproxy\n"); + return (NULL); + } + sc = device_get_softc(miiproxy); + sc->parent = dev; + sc->proxy = miiproxy; + if (rendevous_register_proxy(miiproxy, name, miiproxy_rendevous_callback) != 0) { + device_printf(dev, "can't attach proxy\n"); + return (NULL); + } + device_printf(miiproxy, "attached to target %s\n", device_get_nameunit(sc->mdio)); + return (miiproxy); +} + +static device_method_t miiproxy_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, miiproxy_probe), + DEVMETHOD(device_attach, miiproxy_attach), + DEVMETHOD(device_detach, miiproxy_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + + /* MII interface */ + DEVMETHOD(miibus_readreg, miiproxy_readreg), + DEVMETHOD(miibus_writereg, miiproxy_writereg), + DEVMETHOD(miibus_statchg, miiproxy_statchg), + DEVMETHOD(miibus_linkchg, miiproxy_linkchg), + DEVMETHOD(miibus_mediainit, miiproxy_mediainit), + + DEVMETHOD_END +}; + +static device_method_t mdioproxy_methods[] = { + /* device interface */ + DEVMETHOD(device_identify, mdioproxy_identify), + DEVMETHOD(device_probe, mdioproxy_probe), + DEVMETHOD(device_attach, mdioproxy_attach), + DEVMETHOD(device_detach, mdioproxy_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + + DEVMETHOD_END +}; + +DEFINE_CLASS_0(miiproxy, miiproxy_driver, miiproxy_methods, + sizeof(struct miiproxy_softc)); +DEFINE_CLASS_0(mdioproxy, mdioproxy_driver, mdioproxy_methods, + sizeof(struct mdioproxy_softc)); + +devclass_t miiproxy_devclass; +static devclass_t mdioproxy_devclass; + +DRIVER_MODULE(mdioproxy, mdio, mdioproxy_driver, mdioproxy_devclass, 0, 0); +DRIVER_MODULE(miibus, miiproxy, miibus_driver, miibus_devclass, 0, 0); +MODULE_VERSION(miiproxy, 1); +MODULE_DEPEND(miiproxy, miibus, 1, 1, 1); diff --git a/sys/dev/etherswitch/miiproxy.h b/sys/dev/etherswitch/miiproxy.h new file mode 100644 index 0000000..4883c57 --- /dev/null +++ b/sys/dev/etherswitch/miiproxy.h @@ -0,0 +1,37 @@ +/*- + * Copyright (c) 2011-2012 Stefan Bethke. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef __DEV_ETHERSWITCH_MIIPROXY_H__ +#define __DEV_ETHERSWITCH_MIIPROXY_H__ + +extern devclass_t miiproxy_devclass; +extern driver_t miiproxy_driver; + +device_t mii_attach_proxy(device_t dev); + +#endif /* __DEV_ETHERSWITCH_MIIPROXY_H__ */ |