aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmmanuel Vadot <manu@FreeBSD.org>2022-05-13 11:56:36 +0000
committerEmmanuel Vadot <manu@FreeBSD.org>2022-05-25 07:57:10 +0000
commit25d21a845223ffad189fd2a7831ebf5e298b628a (patch)
tree050f05f62250b7a107f4dae4cf3922014d3b1c28
parentad51c47fb43139b49aafdde615f9e21cbc943238 (diff)
downloadsrc-25d21a845223ffad189fd2a7831ebf5e298b628a.tar.gz
src-25d21a845223ffad189fd2a7831ebf5e298b628a.zip
linuxkpi: Rework detach function
We need to detach the matching i2c adapter so look for the right one. While here add some locks to protect multiple add/del at the same time. Fixes: 1961a14a47 ("linuxkpi: Add i2c support") Sponsored by: Beckhoff Automation GmbH & Co. KG
-rw-r--r--sys/compat/linuxkpi/common/src/linux_i2c.c70
-rw-r--r--sys/compat/linuxkpi/common/src/linux_i2cbb.c10
-rw-r--r--sys/compat/linuxkpi/common/src/lkpi_iic_if.m4
3 files changed, 76 insertions, 8 deletions
diff --git a/sys/compat/linuxkpi/common/src/linux_i2c.c b/sys/compat/linuxkpi/common/src/linux_i2c.c
index 2b19aec8ad16..c2c4977eb9ba 100644
--- a/sys/compat/linuxkpi/common/src/linux_i2c.c
+++ b/sys/compat/linuxkpi/common/src/linux_i2c.c
@@ -53,6 +53,27 @@ struct lkpi_iic_softc {
struct i2c_adapter *adapter;
};
+static struct sx lkpi_sx_i2c;
+
+static void
+lkpi_sysinit_i2c(void *arg __unused)
+{
+
+ sx_init(&lkpi_sx_i2c, "lkpi-i2c");
+}
+
+static void
+lkpi_sysuninit_i2c(void *arg __unused)
+{
+
+ sx_destroy(&lkpi_sx_i2c);
+}
+
+SYSINIT(lkpi_i2c, SI_SUB_DRIVERS, SI_ORDER_ANY,
+ lkpi_sysinit_i2c, NULL);
+SYSUNINIT(lkpi_i2c, SI_SUB_DRIVERS, SI_ORDER_ANY,
+ lkpi_sysuninit_i2c, NULL);
+
static int
lkpi_iic_probe(device_t dev)
{
@@ -98,6 +119,15 @@ lkpi_iic_add_adapter(device_t dev, struct i2c_adapter *adapter)
return (0);
}
+static struct i2c_adapter *
+lkpi_iic_get_adapter(device_t dev)
+{
+ struct lkpi_iic_softc *sc;
+
+ sc = device_get_softc(dev);
+ return (sc->adapter);
+}
+
static device_method_t lkpi_iic_methods[] = {
/* device interface */
DEVMETHOD(device_probe, lkpi_iic_probe),
@@ -113,6 +143,7 @@ static device_method_t lkpi_iic_methods[] = {
/* lkpi_iic interface */
DEVMETHOD(lkpi_iic_add_adapter, lkpi_iic_add_adapter),
+ DEVMETHOD(lkpi_iic_get_adapter, lkpi_iic_get_adapter),
DEVMETHOD_END
};
@@ -177,12 +208,16 @@ lkpi_i2c_add_adapter(struct i2c_adapter *adapter)
device_t lkpi_iic;
int error;
+ if (adapter->name[0] == '\0')
+ return (-EINVAL);
if (bootverbose)
device_printf(adapter->dev.parent->bsddev,
"Adding i2c adapter %s\n", adapter->name);
+ sx_xlock(&lkpi_sx_i2c);
lkpi_iic = device_add_child(adapter->dev.parent->bsddev, "lkpi_iic", -1);
if (lkpi_iic == NULL) {
device_printf(adapter->dev.parent->bsddev, "Couldn't add lkpi_iic\n");
+ sx_xunlock(&lkpi_sx_i2c);
return (ENXIO);
}
@@ -190,9 +225,11 @@ lkpi_i2c_add_adapter(struct i2c_adapter *adapter)
if (error) {
device_printf(adapter->dev.parent->bsddev,
"failed to attach child: error %d\n", error);
+ sx_xunlock(&lkpi_sx_i2c);
return (ENXIO);
}
LKPI_IIC_ADD_ADAPTER(lkpi_iic, adapter);
+ sx_xunlock(&lkpi_sx_i2c);
return (0);
}
@@ -200,18 +237,35 @@ int
lkpi_i2c_del_adapter(struct i2c_adapter *adapter)
{
device_t child;
+ int unit, rv;
+ if (adapter == NULL)
+ return (-EINVAL);
if (bootverbose)
device_printf(adapter->dev.parent->bsddev,
"Removing i2c adapter %s\n", adapter->name);
+ sx_xlock(&lkpi_sx_i2c);
+ unit = 0;
+ while ((child = device_find_child(adapter->dev.parent->bsddev, "lkpi_iic", unit++)) != NULL) {
+
+ if (adapter == LKPI_IIC_GET_ADAPTER(child)) {
+ device_delete_child(adapter->dev.parent->bsddev, child);
+ rv = 0;
+ goto out;
+ }
+ }
- child = device_find_child(adapter->dev.parent->bsddev, "lkpi_iic", -1);
- if (child != NULL)
- device_delete_child(adapter->dev.parent->bsddev, child);
-
- child = device_find_child(adapter->dev.parent->bsddev, "lkpi_iicbb", -1);
- if (child != NULL)
- device_delete_child(adapter->dev.parent->bsddev, child);
+ unit = 0;
+ while ((child = device_find_child(adapter->dev.parent->bsddev, "lkpi_iicbb", unit++)) != NULL) {
- return (0);
+ if (adapter == LKPI_IIC_GET_ADAPTER(child)) {
+ device_delete_child(adapter->dev.parent->bsddev, child);
+ rv = 0;
+ goto out;
+ }
+ }
+ rv = -EINVAL;
+out:
+ sx_xunlock(&lkpi_sx_i2c);
+ return (rv);
}
diff --git a/sys/compat/linuxkpi/common/src/linux_i2cbb.c b/sys/compat/linuxkpi/common/src/linux_i2cbb.c
index 47756a25db3f..c4bfdf32e562 100644
--- a/sys/compat/linuxkpi/common/src/linux_i2cbb.c
+++ b/sys/compat/linuxkpi/common/src/linux_i2cbb.c
@@ -100,6 +100,15 @@ lkpi_iicbb_add_adapter(device_t dev, struct i2c_adapter *adapter)
return (0);
}
+static struct i2c_adapter *
+lkpi_iicbb_get_adapter(device_t dev)
+{
+ struct lkpi_iicbb_softc *sc;
+
+ sc = device_get_softc(dev);
+ return (sc->adapter);
+}
+
static device_method_t lkpi_iicbb_methods[] = {
/* device interface */
DEVMETHOD(device_probe, lkpi_iicbb_probe),
@@ -117,6 +126,7 @@ static device_method_t lkpi_iicbb_methods[] = {
/* lkpi_iicbb interface */
DEVMETHOD(lkpi_iic_add_adapter, lkpi_iicbb_add_adapter),
+ DEVMETHOD(lkpi_iic_get_adapter, lkpi_iicbb_get_adapter),
DEVMETHOD_END
};
diff --git a/sys/compat/linuxkpi/common/src/lkpi_iic_if.m b/sys/compat/linuxkpi/common/src/lkpi_iic_if.m
index 2379182c409b..c1b4abd79084 100644
--- a/sys/compat/linuxkpi/common/src/lkpi_iic_if.m
+++ b/sys/compat/linuxkpi/common/src/lkpi_iic_if.m
@@ -35,3 +35,7 @@ METHOD int add_adapter {
device_t dev;
struct i2c_adapter *adapter;
};
+
+METHOD struct i2c_adapter * get_adapter {
+ device_t dev;
+};