Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev/gpio gpio(4) keeps track of child devices attached u...
details: https://anonhg.NetBSD.org/src/rev/e3ad9f944683
branches: trunk
changeset: 769086:e3ad9f944683
user: mbalmer <mbalmer%NetBSD.org@localhost>
date: Wed Aug 31 12:07:26 2011 +0000
description:
gpio(4) keeps track of child devices attached using the GPIOATTACH ioctl(),
so remove those references and free the memory in gpio_childdetached().
Protect access to the list of child devices with a kcondvar.
diffstat:
sys/dev/gpio/gpio.c | 97 +++++++++++++++++++++++++++++++++++++++++++++-------
1 files changed, 84 insertions(+), 13 deletions(-)
diffs (167 lines):
diff -r 843a6b1abb1a -r e3ad9f944683 sys/dev/gpio/gpio.c
--- a/sys/dev/gpio/gpio.c Wed Aug 31 10:01:18 2011 +0000
+++ b/sys/dev/gpio/gpio.c Wed Aug 31 12:07:26 2011 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: gpio.c,v 1.38 2011/08/30 07:22:11 mbalmer Exp $ */
+/* $NetBSD: gpio.c,v 1.39 2011/08/31 12:07:26 mbalmer Exp $ */
/* $OpenBSD: gpio.c,v 1.6 2006/01/14 12:33:49 grange Exp $ */
/*
@@ -19,7 +19,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: gpio.c,v 1.38 2011/08/30 07:22:11 mbalmer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: gpio.c,v 1.39 2011/08/31 12:07:26 mbalmer Exp $");
/*
* General Purpose Input/Output framework.
@@ -63,6 +63,8 @@
kmutex_t sc_mtx;
kcondvar_t sc_ioctl; /* ioctl in progress */
int sc_ioctl_busy; /* ioctl is busy */
+ kcondvar_t sc_attach; /* attach/detach in progress */
+ int sc_attach_busy;/* busy in attach/detach */
LIST_HEAD(, gpio_dev) sc_devs; /* devices */
LIST_HEAD(, gpio_name) sc_names; /* named pins */
};
@@ -134,7 +136,40 @@
static void
gpio_childdetached(device_t self, device_t child)
{
- /* gpio(4) keeps no references to its children, so do nothing. */
+ struct gpio_dev *gdev;
+ struct gpio_softc *sc;
+ int error;
+
+ /*
+ * gpio_childetached is serialized because it can be entered in
+ * different ways concurrently, e.g. via the GPIODETACH ioctl and
+ * drvctl(8) or modunload(8).
+ */
+ sc = device_private(self);
+ error = 0;
+ mutex_enter(&sc->sc_mtx);
+ while (sc->sc_attach_busy) {
+ error = cv_wait_sig(&sc->sc_attach, &sc->sc_mtx);
+ if (error)
+ break;
+ }
+ if (!error)
+ sc->sc_attach_busy = 1;
+ mutex_exit(&sc->sc_mtx);
+ if (error)
+ return;
+
+ LIST_FOREACH(gdev, &sc->sc_devs, sc_next)
+ if (gdev->sc_dev == child) {
+ LIST_REMOVE(gdev, sc_next);
+ kmem_free(gdev, sizeof(struct gpio_dev));
+ break;
+ }
+
+ mutex_enter(&sc->sc_mtx);
+ sc->sc_attach_busy = 0;
+ cv_signal(&sc->sc_attach);
+ mutex_exit(&sc->sc_mtx);
}
static int
@@ -169,7 +204,7 @@
aprint_error_dev(self, "couldn't establish power handler\n");
mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_VM);
cv_init(&sc->sc_ioctl, "gpioctl");
-
+ cv_init(&sc->sc_attach, "gpioatch");
/*
* Attach all devices that can be connected to the GPIO pins
* described in the kernel configuration file.
@@ -478,7 +513,7 @@
cfdata_t cf;
kauth_cred_t cred;
int locs[GPIOCF_NLOCS];
- int pin, value, flags, npins;
+ int error, pin, value, flags, npins;
gc = sc->sc_gc;
@@ -642,6 +677,19 @@
if (!gpio_pin_can_map(sc, attach->ga_offset, attach->ga_mask))
return EBUSY;
+ error = 0;
+ mutex_enter(&sc->sc_mtx);
+ while (sc->sc_attach_busy) {
+ error = cv_wait_sig(&sc->sc_attach, &sc->sc_mtx);
+ if (error)
+ break;
+ }
+ if (!error)
+ sc->sc_attach_busy = 1;
+ mutex_exit(&sc->sc_mtx);
+ if (error)
+ return EBUSY;
+
ga.ga_gpio = sc;
ga.ga_dvname = attach->ga_dvname;
ga.ga_offset = attach->ga_offset;
@@ -664,28 +712,51 @@
gdev->sc_dev = dv;
LIST_INSERT_HEAD(&sc->sc_devs, gdev, sc_next);
} else
- return EINVAL;
+ error = EINVAL;
} else
- return EINVAL;
- return 0;
+ error = EINVAL;
+ mutex_enter(&sc->sc_mtx);
+ sc->sc_attach_busy = 0;
+ cv_signal(&sc->sc_attach);
+ mutex_exit(&sc->sc_mtx);
+ return error;
case GPIODETACH:
if (kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET,
NULL, NULL, NULL, NULL))
return EPERM;
+ mutex_enter(&sc->sc_mtx);
+ while (sc->sc_attach_busy) {
+ error = cv_wait_sig(&sc->sc_attach, &sc->sc_mtx);
+ if (error)
+ break;
+ }
+ if (!error)
+ sc->sc_attach_busy = 1;
+ mutex_exit(&sc->sc_mtx);
+ if (error)
+ return EBUSY;
+
attach = (struct gpio_attach *)data;
LIST_FOREACH(gdev, &sc->sc_devs, sc_next) {
if (strcmp(device_xname(gdev->sc_dev),
attach->ga_dvname) == 0) {
- if (config_detach(gdev->sc_dev, 0) == 0) {
- LIST_REMOVE(gdev, sc_next);
- kmem_free(gdev,
- sizeof(struct gpio_dev));
+ mutex_enter(&sc->sc_mtx);
+ sc->sc_attach_busy = 0;
+ cv_signal(&sc->sc_attach);
+ mutex_exit(&sc->sc_mtx);
+
+ if (config_detach(gdev->sc_dev, 0) == 0)
return 0;
- }
break;
}
}
+ if (gdev == NULL) {
+ mutex_enter(&sc->sc_mtx);
+ sc->sc_attach_busy = 0;
+ cv_signal(&sc->sc_attach);
+ mutex_exit(&sc->sc_mtx);
+ }
return EINVAL;
case GPIOSET:
if (kauth_authorize_device(cred, KAUTH_DEVICE_GPIO_PINSET,
Home |
Main Index |
Thread Index |
Old Index