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);
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "[email protected]"

Reply via email to