From 2c641c613c7994f7ba296c4d248b5295cfaab572 Mon Sep 17 00:00:00 2001 From: Luiz Souza Date: Thu, 8 Mar 2018 18:28:21 -0300 Subject: Add support for reads and writes on etherswitch. This is aimed to allow firmware or eeprom code updates. (cherry picked from commit a6ab25f81058a51790b0b185e585ecd8f2412551) --- sys/dev/etherswitch/etherswitch.c | 87 +++++++++++++++++++++++++++++++++++- sys/dev/etherswitch/etherswitch_if.m | 69 ++++++++++++++++++++++++++++ 2 files changed, 154 insertions(+), 2 deletions(-) (limited to 'sys') diff --git a/sys/dev/etherswitch/etherswitch.c b/sys/dev/etherswitch/etherswitch.c index 1bc1b2c..0d4d18b 100644 --- a/sys/dev/etherswitch/etherswitch.c +++ b/sys/dev/etherswitch/etherswitch.c @@ -72,13 +72,16 @@ driver_t etherswitch_driver = { sizeof(struct etherswitch_softc), }; -static d_ioctl_t etherswitchioctl; +static d_ioctl_t etherswitchioctl; +static d_read_t etherswitchioread; +static d_write_t etherswitchiowrite; static struct cdevsw etherswitch_cdevsw = { .d_version = D_VERSION, - .d_flags = D_TRACKCLOSE, .d_ioctl = etherswitchioctl, .d_name = "etherswitch", + .d_read = etherswitchioread, + .d_write = etherswitchiowrite, }; static void @@ -215,4 +218,84 @@ etherswitchioctl(struct cdev *cdev, u_long cmd, caddr_t data, int flags, struct return (error); } +static int +etherswitchioread(struct cdev *cdev, struct uio *uio, int ioflag) +{ + device_t etherswitch; + int error; + ssize_t ioblksize, iosize, len; + struct etherswitch_softc *sc; + void *iobuf; + + sc = (struct etherswitch_softc *)cdev->si_drv1; + etherswitch = device_get_parent(sc->sc_dev); + ioblksize = ETHERSWITCH_GETIOBLKSIZE(etherswitch); + iosize = ETHERSWITCH_GETIOSIZE(etherswitch); + iobuf = ETHERSWITCH_GETIOBUF(etherswitch); + if (ioblksize == -1 || iosize == -1 || iobuf == NULL) + return (EINVAL); + if (uio->uio_offset == iosize) + return (0); + if (uio->uio_offset > iosize) + return (EIO); + if (uio->uio_resid > ioblksize) + return (EIO); + + error = 0; + while (uio->uio_resid > 0) { + if (uio->uio_offset >= iosize) + break; + len = MIN(ioblksize - (uio->uio_offset & (ioblksize - 1)), + uio->uio_resid); + error = ETHERSWITCH_IOREAD(etherswitch, uio->uio_offset, len); + if (error != 0) + break; + error = uiomove(iobuf, len, uio); + if (error != 0) + break; + } + + return (error); +} + +static int +etherswitchiowrite(struct cdev *cdev, struct uio *uio, int ioflag) +{ + device_t etherswitch; + int error; + off_t offset; + ssize_t ioblksize, iosize, len; + struct etherswitch_softc *sc; + void *iobuf; + + sc = (struct etherswitch_softc *)cdev->si_drv1; + etherswitch = device_get_parent(sc->sc_dev); + ioblksize = ETHERSWITCH_GETIOBLKSIZE(etherswitch); + iosize = ETHERSWITCH_GETIOSIZE(etherswitch); + iobuf = ETHERSWITCH_GETIOBUF(etherswitch); + if (ioblksize == -1 || iosize == -1 || iobuf == NULL) + return (EINVAL); + if (uio->uio_offset >= iosize) + return (EIO); + if (uio->uio_resid > ioblksize) + return (EIO); + + error = 0; + while (uio->uio_resid > 0) { + if (uio->uio_offset >= iosize) + break; + len = MIN(ioblksize - (uio->uio_offset & (ioblksize - 1)), + uio->uio_resid); + offset = uio->uio_offset; + error = uiomove(iobuf, len, uio); + if (error != 0) + break; + error = ETHERSWITCH_IOWRITE(etherswitch, offset, len); + if (error != 0) + break; + } + + return (0); +} + MODULE_VERSION(etherswitch, 1); diff --git a/sys/dev/etherswitch/etherswitch_if.m b/sys/dev/etherswitch/etherswitch_if.m index 54ac38c..b684027 100644 --- a/sys/dev/etherswitch/etherswitch_if.m +++ b/sys/dev/etherswitch/etherswitch_if.m @@ -47,6 +47,36 @@ CODE { { return (0); } + + static ssize_t + null_etherswitch_getioblksize(device_t dev) + { + return (-1); + } + + static ssize_t + null_etherswitch_getiosize(device_t dev) + { + return (-1); + } + + static void * + null_etherswitch_getiobuf(device_t dev) + { + return (NULL); + } + + static int + null_etherswitch_ioread(device_t dev, off_t off, ssize_t len) + { + return (EIO); + } + + static int + null_etherswitch_iowrite(device_t dev, off_t off, ssize_t len) + { + return (EIO); + } }; # @@ -169,3 +199,42 @@ METHOD int setconf { device_t dev; etherswitch_conf_t *conf; } DEFAULT null_etherswitch_setconf; + +# +# Get the IO buffer block size +# +METHOD ssize_t getioblksize { + device_t dev; +} DEFAULT null_etherswitch_getioblksize; + +# +# Get the IO buffer size +# +METHOD ssize_t getiosize { + device_t dev; +} DEFAULT null_etherswitch_getiosize; + +# +# Get the IO buffer +# +METHOD void * getiobuf { + device_t dev; +} DEFAULT null_etherswitch_getiobuf; + +# +# Perform a read operation and save data into IO buffer +# +METHOD int ioread { + device_t dev; + off_t off; + ssize_t len; +} DEFAULT null_etherswitch_ioread; + +# +# Perform a write operation (write the data in the IO buffer) +# +METHOD int iowrite { + device_t dev; + off_t off; + ssize_t len; +} DEFAULT null_etherswitch_iowrite; -- cgit v1.1