14574da7fSAdrian Chadd /*- 24574da7fSAdrian Chadd * Copyright (c) 2011-2012 Stefan Bethke. 34574da7fSAdrian Chadd * All rights reserved. 44574da7fSAdrian Chadd * 54574da7fSAdrian Chadd * Redistribution and use in source and binary forms, with or without 64574da7fSAdrian Chadd * modification, are permitted provided that the following conditions 74574da7fSAdrian Chadd * are met: 84574da7fSAdrian Chadd * 1. Redistributions of source code must retain the above copyright 94574da7fSAdrian Chadd * notice, this list of conditions and the following disclaimer. 104574da7fSAdrian Chadd * 2. Redistributions in binary form must reproduce the above copyright 114574da7fSAdrian Chadd * notice, this list of conditions and the following disclaimer in the 124574da7fSAdrian Chadd * documentation and/or other materials provided with the distribution. 134574da7fSAdrian Chadd * 144574da7fSAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 154574da7fSAdrian Chadd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 164574da7fSAdrian Chadd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 174574da7fSAdrian Chadd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 184574da7fSAdrian Chadd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 194574da7fSAdrian Chadd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 204574da7fSAdrian Chadd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 214574da7fSAdrian Chadd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 224574da7fSAdrian Chadd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 234574da7fSAdrian Chadd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 244574da7fSAdrian Chadd * SUCH DAMAGE. 254574da7fSAdrian Chadd * 264574da7fSAdrian Chadd * $FreeBSD$ 274574da7fSAdrian Chadd */ 284574da7fSAdrian Chadd 294574da7fSAdrian Chadd #include <sys/param.h> 304574da7fSAdrian Chadd #include <sys/bus.h> 314574da7fSAdrian Chadd #include <sys/kernel.h> 32104dc214SGleb Smirnoff #include <sys/malloc.h> 334574da7fSAdrian Chadd #include <sys/module.h> 344574da7fSAdrian Chadd #include <sys/socket.h> 354574da7fSAdrian Chadd #include <sys/sockio.h> 364574da7fSAdrian Chadd #include <sys/systm.h> 374574da7fSAdrian Chadd 384574da7fSAdrian Chadd #include <net/if.h> 394574da7fSAdrian Chadd #include <net/if_media.h> 404574da7fSAdrian Chadd 414574da7fSAdrian Chadd #include <dev/etherswitch/miiproxy.h> 424574da7fSAdrian Chadd #include <dev/mii/mii.h> 434574da7fSAdrian Chadd #include <dev/mii/miivar.h> 444574da7fSAdrian Chadd 454574da7fSAdrian Chadd #include "mdio_if.h" 464574da7fSAdrian Chadd #include "miibus_if.h" 474574da7fSAdrian Chadd 484574da7fSAdrian Chadd 494574da7fSAdrian Chadd MALLOC_DECLARE(M_MIIPROXY); 504574da7fSAdrian Chadd MALLOC_DEFINE(M_MIIPROXY, "miiproxy", "miiproxy data structures"); 514574da7fSAdrian Chadd 524574da7fSAdrian Chadd driver_t miiproxy_driver; 534574da7fSAdrian Chadd driver_t mdioproxy_driver; 544574da7fSAdrian Chadd 554574da7fSAdrian Chadd struct miiproxy_softc { 564574da7fSAdrian Chadd device_t parent; 574574da7fSAdrian Chadd device_t proxy; 584574da7fSAdrian Chadd device_t mdio; 594574da7fSAdrian Chadd }; 604574da7fSAdrian Chadd 614574da7fSAdrian Chadd struct mdioproxy_softc { 624574da7fSAdrian Chadd }; 634574da7fSAdrian Chadd 644574da7fSAdrian Chadd /* 65*52f24367SRui Paulo * The rendezvous data structures and functions allow two device endpoints to 664574da7fSAdrian Chadd * match up, so that the proxy endpoint can be associated with a target 674574da7fSAdrian Chadd * endpoint. The proxy has to know the device name of the target that it 68*52f24367SRui Paulo * wants to associate with, for example through a hint. The rendezvous code 694574da7fSAdrian Chadd * makes no assumptions about the devices that want to meet. 704574da7fSAdrian Chadd */ 71*52f24367SRui Paulo struct rendezvous_entry; 724574da7fSAdrian Chadd 73*52f24367SRui Paulo enum rendezvous_op { 74*52f24367SRui Paulo RENDEZVOUS_ATTACH, 75*52f24367SRui Paulo RENDEZVOUS_DETACH 764574da7fSAdrian Chadd }; 774574da7fSAdrian Chadd 78*52f24367SRui Paulo typedef int (*rendezvous_callback_t)(enum rendezvous_op, 79*52f24367SRui Paulo struct rendezvous_entry *); 804574da7fSAdrian Chadd 81*52f24367SRui Paulo static SLIST_HEAD(rendezvoushead, rendezvous_entry) rendezvoushead = 82*52f24367SRui Paulo SLIST_HEAD_INITIALIZER(rendezvoushead); 834574da7fSAdrian Chadd 84*52f24367SRui Paulo struct rendezvous_endpoint { 854574da7fSAdrian Chadd device_t device; 864574da7fSAdrian Chadd const char *name; 87*52f24367SRui Paulo rendezvous_callback_t callback; 884574da7fSAdrian Chadd }; 894574da7fSAdrian Chadd 90*52f24367SRui Paulo struct rendezvous_entry { 91*52f24367SRui Paulo SLIST_ENTRY(rendezvous_entry) entries; 92*52f24367SRui Paulo struct rendezvous_endpoint proxy; 93*52f24367SRui Paulo struct rendezvous_endpoint target; 944574da7fSAdrian Chadd }; 954574da7fSAdrian Chadd 964574da7fSAdrian Chadd /* 974574da7fSAdrian Chadd * Call the callback routines for both the proxy and the target. If either 984574da7fSAdrian Chadd * returns an error, undo the attachment. 994574da7fSAdrian Chadd */ 1004574da7fSAdrian Chadd static int 101*52f24367SRui Paulo rendezvous_attach(struct rendezvous_entry *e, struct rendezvous_endpoint *ep) 1024574da7fSAdrian Chadd { 1034574da7fSAdrian Chadd int error; 1044574da7fSAdrian Chadd 105*52f24367SRui Paulo error = e->proxy.callback(RENDEZVOUS_ATTACH, e); 1064574da7fSAdrian Chadd if (error == 0) { 107*52f24367SRui Paulo error = e->target.callback(RENDEZVOUS_ATTACH, e); 1084574da7fSAdrian Chadd if (error != 0) { 109*52f24367SRui Paulo e->proxy.callback(RENDEZVOUS_DETACH, e); 1104574da7fSAdrian Chadd ep->device = NULL; 1114574da7fSAdrian Chadd ep->callback = NULL; 1124574da7fSAdrian Chadd } 1134574da7fSAdrian Chadd } 1144574da7fSAdrian Chadd return (error); 1154574da7fSAdrian Chadd } 1164574da7fSAdrian Chadd 1174574da7fSAdrian Chadd /* 118*52f24367SRui Paulo * Create an entry for the proxy in the rendezvous list. The name parameter 1194574da7fSAdrian Chadd * indicates the name of the device that is the target endpoint for this 120*52f24367SRui Paulo * rendezvous. The callback will be invoked as soon as the target is 1214574da7fSAdrian Chadd * registered: either immediately if the target registered itself earlier, 1224574da7fSAdrian Chadd * or once the target registers. Returns ENXIO if the target has not yet 1234574da7fSAdrian Chadd * registered. 1244574da7fSAdrian Chadd */ 1254574da7fSAdrian Chadd static int 126*52f24367SRui Paulo rendezvous_register_proxy(device_t dev, const char *name, 127*52f24367SRui Paulo rendezvous_callback_t callback) 1284574da7fSAdrian Chadd { 129*52f24367SRui Paulo struct rendezvous_entry *e; 1304574da7fSAdrian Chadd 1314574da7fSAdrian Chadd KASSERT(callback != NULL, ("callback must be set")); 132*52f24367SRui Paulo SLIST_FOREACH(e, &rendezvoushead, entries) { 1334574da7fSAdrian Chadd if (strcmp(name, e->target.name) == 0) { 1344574da7fSAdrian Chadd /* the target is already attached */ 1354574da7fSAdrian Chadd e->proxy.name = device_get_nameunit(dev); 1364574da7fSAdrian Chadd e->proxy.device = dev; 1374574da7fSAdrian Chadd e->proxy.callback = callback; 138*52f24367SRui Paulo return (rendezvous_attach(e, &e->proxy)); 1394574da7fSAdrian Chadd } 1404574da7fSAdrian Chadd } 1414574da7fSAdrian Chadd e = malloc(sizeof(*e), M_MIIPROXY, M_WAITOK | M_ZERO); 1424574da7fSAdrian Chadd e->proxy.name = device_get_nameunit(dev); 1434574da7fSAdrian Chadd e->proxy.device = dev; 1444574da7fSAdrian Chadd e->proxy.callback = callback; 1454574da7fSAdrian Chadd e->target.name = name; 146*52f24367SRui Paulo SLIST_INSERT_HEAD(&rendezvoushead, e, entries); 1474574da7fSAdrian Chadd return (ENXIO); 1484574da7fSAdrian Chadd } 1494574da7fSAdrian Chadd 1504574da7fSAdrian Chadd /* 151*52f24367SRui Paulo * Create an entry in the rendezvous list for the target. 1524574da7fSAdrian Chadd * Returns ENXIO if the proxy has not yet registered. 1534574da7fSAdrian Chadd */ 1544574da7fSAdrian Chadd static int 155*52f24367SRui Paulo rendezvous_register_target(device_t dev, rendezvous_callback_t callback) 1564574da7fSAdrian Chadd { 157*52f24367SRui Paulo struct rendezvous_entry *e; 1584574da7fSAdrian Chadd const char *name; 1594574da7fSAdrian Chadd 1604574da7fSAdrian Chadd KASSERT(callback != NULL, ("callback must be set")); 1614574da7fSAdrian Chadd name = device_get_nameunit(dev); 162*52f24367SRui Paulo SLIST_FOREACH(e, &rendezvoushead, entries) { 1634574da7fSAdrian Chadd if (strcmp(name, e->target.name) == 0) { 1644574da7fSAdrian Chadd e->target.device = dev; 1654574da7fSAdrian Chadd e->target.callback = callback; 166*52f24367SRui Paulo return (rendezvous_attach(e, &e->target)); 1674574da7fSAdrian Chadd } 1684574da7fSAdrian Chadd } 1694574da7fSAdrian Chadd e = malloc(sizeof(*e), M_MIIPROXY, M_WAITOK | M_ZERO); 1704574da7fSAdrian Chadd e->target.name = name; 1714574da7fSAdrian Chadd e->target.device = dev; 1724574da7fSAdrian Chadd e->target.callback = callback; 173*52f24367SRui Paulo SLIST_INSERT_HEAD(&rendezvoushead, e, entries); 1744574da7fSAdrian Chadd return (ENXIO); 1754574da7fSAdrian Chadd } 1764574da7fSAdrian Chadd 1774574da7fSAdrian Chadd /* 1784574da7fSAdrian Chadd * Remove the registration for the proxy. 1794574da7fSAdrian Chadd */ 1804574da7fSAdrian Chadd static int 181*52f24367SRui Paulo rendezvous_unregister_proxy(device_t dev) 1824574da7fSAdrian Chadd { 183*52f24367SRui Paulo struct rendezvous_entry *e; 1844574da7fSAdrian Chadd int error = 0; 1854574da7fSAdrian Chadd 186*52f24367SRui Paulo SLIST_FOREACH(e, &rendezvoushead, entries) { 1874574da7fSAdrian Chadd if (e->proxy.device == dev) { 1884574da7fSAdrian Chadd if (e->target.device == NULL) { 189*52f24367SRui Paulo SLIST_REMOVE(&rendezvoushead, e, rendezvous_entry, entries); 1904574da7fSAdrian Chadd free(e, M_MIIPROXY); 1914574da7fSAdrian Chadd return (0); 1924574da7fSAdrian Chadd } else { 193*52f24367SRui Paulo e->proxy.callback(RENDEZVOUS_DETACH, e); 194*52f24367SRui Paulo e->target.callback(RENDEZVOUS_DETACH, e); 1954574da7fSAdrian Chadd } 1964574da7fSAdrian Chadd e->proxy.device = NULL; 1974574da7fSAdrian Chadd e->proxy.callback = NULL; 1984574da7fSAdrian Chadd return (error); 1994574da7fSAdrian Chadd } 2004574da7fSAdrian Chadd } 2014574da7fSAdrian Chadd return (ENOENT); 2024574da7fSAdrian Chadd } 2034574da7fSAdrian Chadd 2044574da7fSAdrian Chadd /* 2054574da7fSAdrian Chadd * Remove the registration for the target. 2064574da7fSAdrian Chadd */ 2074574da7fSAdrian Chadd static int 208*52f24367SRui Paulo rendezvous_unregister_target(device_t dev) 2094574da7fSAdrian Chadd { 210*52f24367SRui Paulo struct rendezvous_entry *e; 2114574da7fSAdrian Chadd int error = 0; 2124574da7fSAdrian Chadd 213*52f24367SRui Paulo SLIST_FOREACH(e, &rendezvoushead, entries) { 2144574da7fSAdrian Chadd if (e->target.device == dev) { 2154574da7fSAdrian Chadd if (e->proxy.device == NULL) { 216*52f24367SRui Paulo SLIST_REMOVE(&rendezvoushead, e, rendezvous_entry, entries); 2174574da7fSAdrian Chadd free(e, M_MIIPROXY); 2184574da7fSAdrian Chadd return (0); 2194574da7fSAdrian Chadd } else { 220*52f24367SRui Paulo e->proxy.callback(RENDEZVOUS_DETACH, e); 221*52f24367SRui Paulo e->target.callback(RENDEZVOUS_DETACH, e); 2224574da7fSAdrian Chadd } 2234574da7fSAdrian Chadd e->target.device = NULL; 2244574da7fSAdrian Chadd e->target.callback = NULL; 2254574da7fSAdrian Chadd return (error); 2264574da7fSAdrian Chadd } 2274574da7fSAdrian Chadd } 2284574da7fSAdrian Chadd return (ENOENT); 2294574da7fSAdrian Chadd } 2304574da7fSAdrian Chadd 2314574da7fSAdrian Chadd /* 2324574da7fSAdrian Chadd * Functions of the proxy that is interposed between the ethernet interface 2334574da7fSAdrian Chadd * driver and the miibus device. 2344574da7fSAdrian Chadd */ 2354574da7fSAdrian Chadd 2364574da7fSAdrian Chadd static int 237*52f24367SRui Paulo miiproxy_rendezvous_callback(enum rendezvous_op op, struct rendezvous_entry *rendezvous) 2384574da7fSAdrian Chadd { 239*52f24367SRui Paulo struct miiproxy_softc *sc = device_get_softc(rendezvous->proxy.device); 2404574da7fSAdrian Chadd 2414574da7fSAdrian Chadd switch (op) { 242*52f24367SRui Paulo case RENDEZVOUS_ATTACH: 243*52f24367SRui Paulo sc->mdio = device_get_parent(rendezvous->target.device); 2444574da7fSAdrian Chadd break; 245*52f24367SRui Paulo case RENDEZVOUS_DETACH: 2464574da7fSAdrian Chadd sc->mdio = NULL; 2474574da7fSAdrian Chadd break; 2484574da7fSAdrian Chadd } 2494574da7fSAdrian Chadd return (0); 2504574da7fSAdrian Chadd } 2514574da7fSAdrian Chadd 2524574da7fSAdrian Chadd static int 2534574da7fSAdrian Chadd miiproxy_probe(device_t dev) 2544574da7fSAdrian Chadd { 2554574da7fSAdrian Chadd device_set_desc(dev, "MII/MDIO proxy, MII side"); 2564574da7fSAdrian Chadd 2574574da7fSAdrian Chadd return (BUS_PROBE_SPECIFIC); 2584574da7fSAdrian Chadd } 2594574da7fSAdrian Chadd 2604574da7fSAdrian Chadd static int 2614574da7fSAdrian Chadd miiproxy_attach(device_t dev) 2624574da7fSAdrian Chadd { 2634574da7fSAdrian Chadd 2644574da7fSAdrian Chadd /* 2654574da7fSAdrian Chadd * The ethernet interface needs to call mii_attach_proxy() to pass 266*52f24367SRui Paulo * the relevant parameters for rendezvous with the MDIO target. 2674574da7fSAdrian Chadd */ 2684574da7fSAdrian Chadd return (bus_generic_attach(dev)); 2694574da7fSAdrian Chadd } 2704574da7fSAdrian Chadd 2714574da7fSAdrian Chadd static int 2724574da7fSAdrian Chadd miiproxy_detach(device_t dev) 2734574da7fSAdrian Chadd { 2744574da7fSAdrian Chadd 275*52f24367SRui Paulo rendezvous_unregister_proxy(dev); 2764574da7fSAdrian Chadd bus_generic_detach(dev); 2774574da7fSAdrian Chadd return (0); 2784574da7fSAdrian Chadd } 2794574da7fSAdrian Chadd 2804574da7fSAdrian Chadd static int 2814574da7fSAdrian Chadd miiproxy_readreg(device_t dev, int phy, int reg) 2824574da7fSAdrian Chadd { 2834574da7fSAdrian Chadd struct miiproxy_softc *sc = device_get_softc(dev); 2844574da7fSAdrian Chadd 2854574da7fSAdrian Chadd if (sc->mdio != NULL) 2864574da7fSAdrian Chadd return (MDIO_READREG(sc->mdio, phy, reg)); 2874574da7fSAdrian Chadd return (-1); 2884574da7fSAdrian Chadd } 2894574da7fSAdrian Chadd 2904574da7fSAdrian Chadd static int 2914574da7fSAdrian Chadd miiproxy_writereg(device_t dev, int phy, int reg, int val) 2924574da7fSAdrian Chadd { 2934574da7fSAdrian Chadd struct miiproxy_softc *sc = device_get_softc(dev); 2944574da7fSAdrian Chadd 2954574da7fSAdrian Chadd if (sc->mdio != NULL) 2964574da7fSAdrian Chadd return (MDIO_WRITEREG(sc->mdio, phy, reg, val)); 2974574da7fSAdrian Chadd return (-1); 2984574da7fSAdrian Chadd } 2994574da7fSAdrian Chadd 3004574da7fSAdrian Chadd static void 3014574da7fSAdrian Chadd miiproxy_statchg(device_t dev) 3024574da7fSAdrian Chadd { 3034574da7fSAdrian Chadd 3044574da7fSAdrian Chadd MIIBUS_STATCHG(device_get_parent(dev)); 3054574da7fSAdrian Chadd } 3064574da7fSAdrian Chadd 3074574da7fSAdrian Chadd static void 3084574da7fSAdrian Chadd miiproxy_linkchg(device_t dev) 3094574da7fSAdrian Chadd { 3104574da7fSAdrian Chadd 3114574da7fSAdrian Chadd MIIBUS_LINKCHG(device_get_parent(dev)); 3124574da7fSAdrian Chadd } 3134574da7fSAdrian Chadd 3144574da7fSAdrian Chadd static void 3154574da7fSAdrian Chadd miiproxy_mediainit(device_t dev) 3164574da7fSAdrian Chadd { 3174574da7fSAdrian Chadd 3184574da7fSAdrian Chadd MIIBUS_MEDIAINIT(device_get_parent(dev)); 3194574da7fSAdrian Chadd } 3204574da7fSAdrian Chadd 3214574da7fSAdrian Chadd /* 3224574da7fSAdrian Chadd * Functions for the MDIO target device driver. 3234574da7fSAdrian Chadd */ 3244574da7fSAdrian Chadd static int 325*52f24367SRui Paulo mdioproxy_rendezvous_callback(enum rendezvous_op op, struct rendezvous_entry *rendezvous) 3264574da7fSAdrian Chadd { 3274574da7fSAdrian Chadd return (0); 3284574da7fSAdrian Chadd } 3294574da7fSAdrian Chadd 3304574da7fSAdrian Chadd static void 3314574da7fSAdrian Chadd mdioproxy_identify(driver_t *driver, device_t parent) 3324574da7fSAdrian Chadd { 3334574da7fSAdrian Chadd device_t child; 3344574da7fSAdrian Chadd 3354574da7fSAdrian Chadd if (device_find_child(parent, driver->name, -1) == NULL) { 3364574da7fSAdrian Chadd child = BUS_ADD_CHILD(parent, 0, driver->name, -1); 3374574da7fSAdrian Chadd } 3384574da7fSAdrian Chadd } 3394574da7fSAdrian Chadd 3404574da7fSAdrian Chadd static int 3414574da7fSAdrian Chadd mdioproxy_probe(device_t dev) 3424574da7fSAdrian Chadd { 3434574da7fSAdrian Chadd device_set_desc(dev, "MII/MDIO proxy, MDIO side"); 3444574da7fSAdrian Chadd 3454574da7fSAdrian Chadd return (BUS_PROBE_SPECIFIC); 3464574da7fSAdrian Chadd } 3474574da7fSAdrian Chadd 3484574da7fSAdrian Chadd static int 3494574da7fSAdrian Chadd mdioproxy_attach(device_t dev) 3504574da7fSAdrian Chadd { 3514574da7fSAdrian Chadd 352*52f24367SRui Paulo rendezvous_register_target(dev, mdioproxy_rendezvous_callback); 3534574da7fSAdrian Chadd return (bus_generic_attach(dev)); 3544574da7fSAdrian Chadd } 3554574da7fSAdrian Chadd 3564574da7fSAdrian Chadd static int 3574574da7fSAdrian Chadd mdioproxy_detach(device_t dev) 3584574da7fSAdrian Chadd { 3594574da7fSAdrian Chadd 360*52f24367SRui Paulo rendezvous_unregister_target(dev); 3614574da7fSAdrian Chadd bus_generic_detach(dev); 3624574da7fSAdrian Chadd return (0); 3634574da7fSAdrian Chadd } 3644574da7fSAdrian Chadd 3654574da7fSAdrian Chadd /* 3664574da7fSAdrian Chadd * Attach this proxy in place of miibus. The target MDIO must be attached 3674574da7fSAdrian Chadd * already. Returns NULL on error. 3684574da7fSAdrian Chadd */ 3694574da7fSAdrian Chadd device_t 3704574da7fSAdrian Chadd mii_attach_proxy(device_t dev) 3714574da7fSAdrian Chadd { 3724574da7fSAdrian Chadd struct miiproxy_softc *sc; 3734574da7fSAdrian Chadd int error; 3744574da7fSAdrian Chadd const char *name; 3754574da7fSAdrian Chadd device_t miiproxy; 3764574da7fSAdrian Chadd 3774574da7fSAdrian Chadd if (resource_string_value(device_get_name(dev), 3784574da7fSAdrian Chadd device_get_unit(dev), "mdio", &name) != 0) { 3794574da7fSAdrian Chadd if (bootverbose) 3804574da7fSAdrian Chadd printf("mii_attach_proxy: not attaching, no mdio" 3814574da7fSAdrian Chadd " device hint for %s\n", device_get_nameunit(dev)); 3824574da7fSAdrian Chadd return (NULL); 3834574da7fSAdrian Chadd } 3844574da7fSAdrian Chadd 3854574da7fSAdrian Chadd miiproxy = device_add_child(dev, miiproxy_driver.name, -1); 3864574da7fSAdrian Chadd error = bus_generic_attach(dev); 3874574da7fSAdrian Chadd if (error != 0) { 3884574da7fSAdrian Chadd device_printf(dev, "can't attach miiproxy\n"); 3894574da7fSAdrian Chadd return (NULL); 3904574da7fSAdrian Chadd } 3914574da7fSAdrian Chadd sc = device_get_softc(miiproxy); 3924574da7fSAdrian Chadd sc->parent = dev; 3934574da7fSAdrian Chadd sc->proxy = miiproxy; 394*52f24367SRui Paulo if (rendezvous_register_proxy(miiproxy, name, miiproxy_rendezvous_callback) != 0) { 3954574da7fSAdrian Chadd device_printf(dev, "can't attach proxy\n"); 3964574da7fSAdrian Chadd return (NULL); 3974574da7fSAdrian Chadd } 3984574da7fSAdrian Chadd device_printf(miiproxy, "attached to target %s\n", device_get_nameunit(sc->mdio)); 3994574da7fSAdrian Chadd return (miiproxy); 4004574da7fSAdrian Chadd } 4014574da7fSAdrian Chadd 4024574da7fSAdrian Chadd static device_method_t miiproxy_methods[] = { 4034574da7fSAdrian Chadd /* device interface */ 4044574da7fSAdrian Chadd DEVMETHOD(device_probe, miiproxy_probe), 4054574da7fSAdrian Chadd DEVMETHOD(device_attach, miiproxy_attach), 4064574da7fSAdrian Chadd DEVMETHOD(device_detach, miiproxy_detach), 4074574da7fSAdrian Chadd DEVMETHOD(device_shutdown, bus_generic_shutdown), 4084574da7fSAdrian Chadd 4094574da7fSAdrian Chadd /* MII interface */ 4104574da7fSAdrian Chadd DEVMETHOD(miibus_readreg, miiproxy_readreg), 4114574da7fSAdrian Chadd DEVMETHOD(miibus_writereg, miiproxy_writereg), 4124574da7fSAdrian Chadd DEVMETHOD(miibus_statchg, miiproxy_statchg), 4134574da7fSAdrian Chadd DEVMETHOD(miibus_linkchg, miiproxy_linkchg), 4144574da7fSAdrian Chadd DEVMETHOD(miibus_mediainit, miiproxy_mediainit), 4154574da7fSAdrian Chadd 4164574da7fSAdrian Chadd DEVMETHOD_END 4174574da7fSAdrian Chadd }; 4184574da7fSAdrian Chadd 4194574da7fSAdrian Chadd static device_method_t mdioproxy_methods[] = { 4204574da7fSAdrian Chadd /* device interface */ 4214574da7fSAdrian Chadd DEVMETHOD(device_identify, mdioproxy_identify), 4224574da7fSAdrian Chadd DEVMETHOD(device_probe, mdioproxy_probe), 4234574da7fSAdrian Chadd DEVMETHOD(device_attach, mdioproxy_attach), 4244574da7fSAdrian Chadd DEVMETHOD(device_detach, mdioproxy_detach), 4254574da7fSAdrian Chadd DEVMETHOD(device_shutdown, bus_generic_shutdown), 4264574da7fSAdrian Chadd 4274574da7fSAdrian Chadd DEVMETHOD_END 4284574da7fSAdrian Chadd }; 4294574da7fSAdrian Chadd 4304574da7fSAdrian Chadd DEFINE_CLASS_0(miiproxy, miiproxy_driver, miiproxy_methods, 4314574da7fSAdrian Chadd sizeof(struct miiproxy_softc)); 4324574da7fSAdrian Chadd DEFINE_CLASS_0(mdioproxy, mdioproxy_driver, mdioproxy_methods, 4334574da7fSAdrian Chadd sizeof(struct mdioproxy_softc)); 4344574da7fSAdrian Chadd 4354574da7fSAdrian Chadd devclass_t miiproxy_devclass; 4364574da7fSAdrian Chadd static devclass_t mdioproxy_devclass; 4374574da7fSAdrian Chadd 4384574da7fSAdrian Chadd DRIVER_MODULE(mdioproxy, mdio, mdioproxy_driver, mdioproxy_devclass, 0, 0); 4394574da7fSAdrian Chadd DRIVER_MODULE(miibus, miiproxy, miibus_driver, miibus_devclass, 0, 0); 4404574da7fSAdrian Chadd MODULE_VERSION(miiproxy, 1); 4414574da7fSAdrian Chadd MODULE_DEPEND(miiproxy, miibus, 1, 1, 1); 442