1235288Sadrian/*- 2235288Sadrian * Copyright (c) 2011-2012 Stefan Bethke. 3235288Sadrian * All rights reserved. 4235288Sadrian * 5235288Sadrian * Redistribution and use in source and binary forms, with or without 6235288Sadrian * modification, are permitted provided that the following conditions 7235288Sadrian * are met: 8235288Sadrian * 1. Redistributions of source code must retain the above copyright 9235288Sadrian * notice, this list of conditions and the following disclaimer. 10235288Sadrian * 2. Redistributions in binary form must reproduce the above copyright 11235288Sadrian * notice, this list of conditions and the following disclaimer in the 12235288Sadrian * documentation and/or other materials provided with the distribution. 13235288Sadrian * 14235288Sadrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15235288Sadrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16235288Sadrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17235288Sadrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18235288Sadrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19235288Sadrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20235288Sadrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21235288Sadrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22235288Sadrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23235288Sadrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24235288Sadrian * SUCH DAMAGE. 25235288Sadrian * 26235288Sadrian * $FreeBSD: releng/10.3/sys/dev/etherswitch/etherswitch.c 250381 2013-05-08 20:46:54Z adrian $ 27235288Sadrian */ 28235288Sadrian 29235288Sadrian#include <sys/param.h> 30235288Sadrian#include <sys/bus.h> 31235288Sadrian#include <sys/conf.h> 32235288Sadrian#include <sys/fcntl.h> 33235288Sadrian#include <sys/lock.h> 34235288Sadrian#include <sys/kernel.h> 35235288Sadrian#include <sys/malloc.h> 36235288Sadrian#include <sys/module.h> 37235288Sadrian#include <sys/socket.h> 38235288Sadrian#include <sys/sx.h> 39235288Sadrian#include <sys/systm.h> 40235288Sadrian#include <sys/uio.h> 41235288Sadrian 42235288Sadrian#include <net/if.h> 43235288Sadrian 44235288Sadrian#include <dev/etherswitch/etherswitch.h> 45235288Sadrian 46235288Sadrian#include "etherswitch_if.h" 47235288Sadrian 48235288Sadrian#define BUFSIZE 1024 49235288Sadrian 50235288Sadrianstruct etherswitch_softc { 51235288Sadrian device_t sc_dev; 52235288Sadrian int sc_count; 53235288Sadrian 54235288Sadrian struct cdev *sc_devnode; 55235288Sadrian struct sx sc_lock; 56235288Sadrian}; 57235288Sadrian 58235288Sadrian#define SWITCH_LOCK(sc) sx_xlock(&(sc)->sc_lock) 59235288Sadrian#define SWITCH_UNLOCK(sc) sx_xunlock(&(sc)->sc_lock) 60235288Sadrian 61235288Sadrianstatic int etherswitch_probe(device_t); 62235288Sadrianstatic int etherswitch_attach(device_t); 63235288Sadrianstatic int etherswitch_detach(device_t); 64235288Sadrianstatic void etherswitch_identify(driver_t *driver, device_t parent); 65235288Sadrian 66235288Sadriandevclass_t etherswitch_devclass; 67235288Sadrian 68235288Sadrianstatic device_method_t etherswitch_methods[] = { 69235288Sadrian /* device interface */ 70235288Sadrian DEVMETHOD(device_identify, etherswitch_identify), 71235288Sadrian DEVMETHOD(device_probe, etherswitch_probe), 72235288Sadrian DEVMETHOD(device_attach, etherswitch_attach), 73235288Sadrian DEVMETHOD(device_detach, etherswitch_detach), 74235288Sadrian 75235288Sadrian { 0, 0 } 76235288Sadrian}; 77235288Sadrian 78235288Sadriandriver_t etherswitch_driver = { 79235288Sadrian "etherswitch", 80235288Sadrian etherswitch_methods, 81235288Sadrian sizeof(struct etherswitch_softc), 82235288Sadrian}; 83235288Sadrian 84235288Sadrianstatic d_open_t etherswitchopen; 85235288Sadrianstatic d_close_t etherswitchclose; 86235288Sadrianstatic d_write_t etherswitchwrite; 87235288Sadrianstatic d_read_t etherswitchread; 88235288Sadrianstatic d_ioctl_t etherswitchioctl; 89235288Sadrian 90235288Sadrianstatic struct cdevsw etherswitch_cdevsw = { 91235288Sadrian .d_version = D_VERSION, 92235288Sadrian .d_flags = D_TRACKCLOSE, 93235288Sadrian .d_open = etherswitchopen, 94235288Sadrian .d_close = etherswitchclose, 95235288Sadrian .d_read = etherswitchread, 96235288Sadrian .d_write = etherswitchwrite, 97235288Sadrian .d_ioctl = etherswitchioctl, 98235288Sadrian .d_name = "etherswitch", 99235288Sadrian}; 100235288Sadrian 101235288Sadrianstatic void 102235288Sadrianetherswitch_identify(driver_t *driver, device_t parent) 103235288Sadrian{ 104235288Sadrian if (device_find_child(parent, "etherswitch", -1) == NULL) 105235288Sadrian BUS_ADD_CHILD(parent, 0, "etherswitch", -1); 106235288Sadrian} 107235288Sadrian 108235288Sadrianstatic int 109235288Sadrianetherswitch_probe(device_t dev) 110235288Sadrian{ 111235288Sadrian device_set_desc(dev, "Switch controller"); 112235288Sadrian 113235288Sadrian return (0); 114235288Sadrian} 115235288Sadrian 116235288Sadrianstatic int 117235288Sadrianetherswitch_attach(device_t dev) 118235288Sadrian{ 119235288Sadrian struct etherswitch_softc *sc = (struct etherswitch_softc *)device_get_softc(dev); 120235288Sadrian 121235288Sadrian sc->sc_dev = dev; 122235288Sadrian sx_init(&sc->sc_lock, "etherswitch"); 123235288Sadrian sc->sc_devnode = make_dev(ðerswitch_cdevsw, device_get_unit(dev), 124235288Sadrian UID_ROOT, GID_WHEEL, 125235288Sadrian 0600, "etherswitch%d", device_get_unit(dev)); 126235288Sadrian if (sc->sc_devnode == NULL) { 127235288Sadrian device_printf(dev, "failed to create character device\n"); 128235288Sadrian sx_destroy(&sc->sc_lock); 129235288Sadrian return (ENXIO); 130235288Sadrian } 131235288Sadrian sc->sc_devnode->si_drv1 = sc; 132235288Sadrian 133235288Sadrian return (0); 134235288Sadrian} 135235288Sadrian 136235288Sadrianstatic int 137235288Sadrianetherswitch_detach(device_t dev) 138235288Sadrian{ 139235288Sadrian struct etherswitch_softc *sc = (struct etherswitch_softc *)device_get_softc(dev); 140235288Sadrian 141235288Sadrian if (sc->sc_devnode) 142235288Sadrian destroy_dev(sc->sc_devnode); 143235288Sadrian sx_destroy(&sc->sc_lock); 144235288Sadrian 145235288Sadrian return (0); 146235288Sadrian} 147235288Sadrian 148235288Sadrianstatic int 149235288Sadrianetherswitchopen(struct cdev *dev, int flags, int fmt, struct thread *td) 150235288Sadrian{ 151235288Sadrian struct etherswitch_softc *sc = dev->si_drv1; 152235288Sadrian 153235288Sadrian SWITCH_LOCK(sc); 154235288Sadrian if (sc->sc_count > 0) { 155235288Sadrian SWITCH_UNLOCK(sc); 156235288Sadrian return (EBUSY); 157235288Sadrian } 158235288Sadrian 159235288Sadrian sc->sc_count++; 160235288Sadrian SWITCH_UNLOCK(sc); 161235288Sadrian 162235288Sadrian return (0); 163235288Sadrian} 164235288Sadrian 165235288Sadrianstatic int 166235288Sadrianetherswitchclose(struct cdev *dev, int flags, int fmt, struct thread *td) 167235288Sadrian{ 168235288Sadrian struct etherswitch_softc *sc = dev->si_drv1; 169235288Sadrian 170235288Sadrian SWITCH_LOCK(sc); 171235288Sadrian if (sc->sc_count == 0) { 172235288Sadrian SWITCH_UNLOCK(sc); 173235288Sadrian return (EINVAL); 174235288Sadrian } 175235288Sadrian 176235288Sadrian sc->sc_count--; 177235288Sadrian 178235288Sadrian if (sc->sc_count < 0) 179235288Sadrian panic("%s: etherswitch_count < 0!", __func__); 180235288Sadrian SWITCH_UNLOCK(sc); 181235288Sadrian 182235288Sadrian return (0); 183235288Sadrian} 184235288Sadrian 185235288Sadrianstatic int 186235288Sadrianetherswitchwrite(struct cdev *dev, struct uio * uio, int ioflag) 187235288Sadrian{ 188235288Sadrian return (EINVAL); 189235288Sadrian} 190235288Sadrian 191235288Sadrianstatic int 192235288Sadrianetherswitchread(struct cdev *dev, struct uio * uio, int ioflag) 193235288Sadrian{ 194235288Sadrian return (EINVAL); 195235288Sadrian} 196235288Sadrian 197235288Sadrianstatic int 198235288Sadrianetherswitchioctl(struct cdev *cdev, u_long cmd, caddr_t data, int flags, struct thread *td) 199235288Sadrian{ 200235288Sadrian struct etherswitch_softc *sc = cdev->si_drv1; 201235288Sadrian device_t dev = sc->sc_dev; 202235288Sadrian device_t etherswitch = device_get_parent(dev); 203250381Sadrian etherswitch_conf_t conf; 204235288Sadrian etherswitch_info_t *info; 205235288Sadrian etherswitch_reg_t *reg; 206235288Sadrian etherswitch_phyreg_t *phyreg; 207235288Sadrian int error = 0; 208235288Sadrian 209235288Sadrian switch (cmd) { 210235288Sadrian case IOETHERSWITCHGETINFO: 211235288Sadrian info = ETHERSWITCH_GETINFO(etherswitch); 212235288Sadrian bcopy(info, data, sizeof(etherswitch_info_t)); 213235288Sadrian break; 214235288Sadrian 215235288Sadrian case IOETHERSWITCHGETREG: 216235288Sadrian reg = (etherswitch_reg_t *)data; 217241578Sray ETHERSWITCH_LOCK(etherswitch); 218235288Sadrian reg->val = ETHERSWITCH_READREG(etherswitch, reg->reg); 219241578Sray ETHERSWITCH_UNLOCK(etherswitch); 220235288Sadrian break; 221235288Sadrian 222235288Sadrian case IOETHERSWITCHSETREG: 223235288Sadrian reg = (etherswitch_reg_t *)data; 224241578Sray ETHERSWITCH_LOCK(etherswitch); 225235288Sadrian error = ETHERSWITCH_WRITEREG(etherswitch, reg->reg, reg->val); 226241578Sray ETHERSWITCH_UNLOCK(etherswitch); 227235288Sadrian break; 228235288Sadrian 229235288Sadrian case IOETHERSWITCHGETPORT: 230235288Sadrian error = ETHERSWITCH_GETPORT(etherswitch, (etherswitch_port_t *)data); 231235288Sadrian break; 232235288Sadrian 233235288Sadrian case IOETHERSWITCHSETPORT: 234235288Sadrian error = ETHERSWITCH_SETPORT(etherswitch, (etherswitch_port_t *)data); 235235288Sadrian break; 236235288Sadrian 237235288Sadrian case IOETHERSWITCHGETVLANGROUP: 238235288Sadrian error = ETHERSWITCH_GETVGROUP(etherswitch, (etherswitch_vlangroup_t *)data); 239235288Sadrian break; 240235288Sadrian 241235288Sadrian case IOETHERSWITCHSETVLANGROUP: 242235288Sadrian error = ETHERSWITCH_SETVGROUP(etherswitch, (etherswitch_vlangroup_t *)data); 243235288Sadrian break; 244235288Sadrian 245235288Sadrian case IOETHERSWITCHGETPHYREG: 246235288Sadrian phyreg = (etherswitch_phyreg_t *)data; 247235288Sadrian phyreg->val = ETHERSWITCH_READPHYREG(etherswitch, phyreg->phy, phyreg->reg); 248235288Sadrian break; 249235288Sadrian 250235288Sadrian case IOETHERSWITCHSETPHYREG: 251235288Sadrian phyreg = (etherswitch_phyreg_t *)data; 252235288Sadrian error = ETHERSWITCH_WRITEPHYREG(etherswitch, phyreg->phy, phyreg->reg, phyreg->val); 253235288Sadrian break; 254235288Sadrian 255250381Sadrian case IOETHERSWITCHGETCONF: 256250381Sadrian bzero(&conf, sizeof(etherswitch_conf_t)); 257250381Sadrian error = ETHERSWITCH_GETCONF(etherswitch, &conf); 258250381Sadrian bcopy(&conf, data, sizeof(etherswitch_conf_t)); 259250381Sadrian break; 260250381Sadrian 261250381Sadrian case IOETHERSWITCHSETCONF: 262250381Sadrian error = ETHERSWITCH_SETCONF(etherswitch, (etherswitch_conf_t *)data); 263250381Sadrian break; 264250381Sadrian 265235288Sadrian default: 266235288Sadrian error = ENOTTY; 267235288Sadrian } 268235288Sadrian 269235288Sadrian return (error); 270235288Sadrian} 271235288Sadrian 272235288SadrianMODULE_VERSION(etherswitch, 1); 273