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.
This commit is contained in:
loos 2015-03-05 02:54:30 +00:00
parent aa6f296074
commit 4655e1ef19

View File

@ -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);