svn commit: r279621 - head/sys/dev/gpio
Luiz Otavio O Souza
loos at FreeBSD.org
Thu Mar 5 02:54:31 UTC 2015
Author: loos
Date: Thu Mar 5 02:54:30 2015
New Revision: 279621
URL: https://svnweb.freebsd.org/changeset/base/279621
Log:
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.
Modified:
head/sys/dev/gpio/ofw_gpiobus.c
Modified: head/sys/dev/gpio/ofw_gpiobus.c
==============================================================================
--- head/sys/dev/gpio/ofw_gpiobus.c Thu Mar 5 01:49:58 2015 (r279620)
+++ head/sys/dev/gpio/ofw_gpiobus.c Thu Mar 5 02:54:30 2015 (r279621)
@@ -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,
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,
}
/* 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);
More information about the svn-src-all
mailing list