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-head mailing list