summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorLuiz Souza <luiz@netgate.com>2018-03-08 18:28:21 -0300
committerLuiz Souza <luiz@netgate.com>2018-03-08 21:50:27 -0600
commit2c641c613c7994f7ba296c4d248b5295cfaab572 (patch)
tree3348ed271d0188901c8c6c4b73b15594650295fd /sys
parentb830726ec00156a59a09c554f49777e5b328df81 (diff)
downloadFreeBSD-src-2c641c613c7994f7ba296c4d248b5295cfaab572.zip
FreeBSD-src-2c641c613c7994f7ba296c4d248b5295cfaab572.tar.gz
Add support for reads and writes on etherswitch.
This is aimed to allow firmware or eeprom code updates. (cherry picked from commit a6ab25f81058a51790b0b185e585ecd8f2412551)
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/etherswitch/etherswitch.c87
-rw-r--r--sys/dev/etherswitch/etherswitch_if.m69
2 files changed, 154 insertions, 2 deletions
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;
OpenPOWER on IntegriCloud