summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorloos <loos@FreeBSD.org>2015-03-05 02:54:30 +0000
committerloos <loos@FreeBSD.org>2015-03-05 02:54:30 +0000
commit4655e1ef1928f6b30c6c5cdddd37c93568152498 (patch)
tree23a27997dbbfb948edc9ff11226105bef50b5ba2
parentaa6f296074ee25ce0a33226d91cd625ecb67acf2 (diff)
downloadFreeBSD-src-4655e1ef1928f6b30c6c5cdddd37c93568152498.zip
FreeBSD-src-4655e1ef1928f6b30c6c5cdddd37c93568152498.tar.gz
Change ofw_gpiobus_destroy_devinfo() to unmap the GPIO pins and then
rework the code a little bit to use this function consistently to cleanup all the changes made as part of the probe phase. This fixes an issue where a FDT child node without a matching driver could leave the GPIO pins mapped and prevent the further use of them.
-rw-r--r--sys/dev/gpio/ofw_gpiobus.c39
1 files changed, 24 insertions, 15 deletions
diff --git a/sys/dev/gpio/ofw_gpiobus.c b/sys/dev/gpio/ofw_gpiobus.c
index be961ea..3eb6b86 100644
--- a/sys/dev/gpio/ofw_gpiobus.c
+++ b/sys/dev/gpio/ofw_gpiobus.c
@@ -41,7 +41,7 @@ __FBSDID("$FreeBSD$");
static struct ofw_gpiobus_devinfo *ofw_gpiobus_setup_devinfo(device_t,
device_t, phandle_t);
-static void ofw_gpiobus_destroy_devinfo(struct ofw_gpiobus_devinfo *);
+static void ofw_gpiobus_destroy_devinfo(device_t, struct ofw_gpiobus_devinfo *);
static int ofw_gpiobus_parse_gpios_impl(device_t, phandle_t, char *,
struct gpiobus_softc *, struct gpiobus_pin **);
@@ -63,7 +63,7 @@ ofw_gpiobus_add_fdt_child(device_t bus, const char *drvname, phandle_t child)
return (NULL);
}
if (device_probe_and_attach(childdev) != 0) {
- ofw_gpiobus_destroy_devinfo(dinfo);
+ ofw_gpiobus_destroy_devinfo(bus, dinfo);
device_delete_child(bus, childdev);
return (NULL);
}
@@ -117,41 +117,50 @@ ofw_gpiobus_setup_devinfo(device_t bus, device_t child, phandle_t node)
}
/* Parse the gpios property for the child. */
npins = ofw_gpiobus_parse_gpios_impl(child, node, "gpios", sc, &pins);
- if (npins <= 0)
- goto fail;
+ if (npins <= 0) {
+ ofw_bus_gen_destroy_devinfo(&dinfo->opd_obdinfo);
+ free(dinfo, M_DEVBUF);
+ return (NULL);
+ }
+ /* Initialize the irq resource list. */
+ resource_list_init(&dinfo->opd_dinfo.rl);
+ /* Allocate the child ivars and copy the parsed pin data. */
devi = &dinfo->opd_dinfo;
devi->npins = (uint32_t)npins;
if (gpiobus_alloc_ivars(devi) != 0) {
free(pins, M_DEVBUF);
- goto fail;
+ ofw_gpiobus_destroy_devinfo(bus, dinfo);
+ return (NULL);
}
for (i = 0; i < devi->npins; i++) {
devi->flags[i] = pins[i].flags;
devi->pins[i] = pins[i].pin;
}
free(pins, M_DEVBUF);
- /* And now the interrupt resources. */
- resource_list_init(&dinfo->opd_dinfo.rl);
+ /* Parse the interrupt resources. */
if (ofw_bus_intr_to_rl(bus, node, &dinfo->opd_dinfo.rl) != 0) {
- gpiobus_free_ivars(devi);
- goto fail;
+ ofw_gpiobus_destroy_devinfo(bus, dinfo);
+ return (NULL);
}
device_set_ivars(child, dinfo);
return (dinfo);
-
-fail:
- ofw_bus_gen_destroy_devinfo(&dinfo->opd_obdinfo);
- free(dinfo, M_DEVBUF);
- return (NULL);
}
static void
-ofw_gpiobus_destroy_devinfo(struct ofw_gpiobus_devinfo *dinfo)
+ofw_gpiobus_destroy_devinfo(device_t bus, struct ofw_gpiobus_devinfo *dinfo)
{
+ int i;
struct gpiobus_ivar *devi;
+ struct gpiobus_softc *sc;
+ sc = device_get_softc(bus);
devi = &dinfo->opd_dinfo;
+ for (i = 0; i < devi->npins; i++) {
+ if (devi->pins[i] > sc->sc_npins)
+ continue;
+ sc->sc_pins_mapped[devi->pins[i]] = 0;
+ }
gpiobus_free_ivars(devi);
resource_list_free(&dinfo->opd_dinfo.rl);
ofw_bus_gen_destroy_devinfo(&dinfo->opd_obdinfo);
OpenPOWER on IntegriCloud