gpio_acpi: Introduce separate setup_intr and teardown_intr functions. master
authorImre Vadász <imre@vdsz.com>
Fri, 29 Apr 2016 20:32:09 +0000 (22:32 +0200)
committerImre Vadász <imre@vdsz.com>
Fri, 29 Apr 2016 21:07:42 +0000 (23:07 +0200)
* This allows us to actually reserve the gpio pin before, and separately
  from actually setting up the interrupt handler.

* XXX This interface is still a bit inconvenient to use, because the
  code allows gpio_setup_intr to fail. Instead the gpio_alloc_intr
  function should be returning a cookie to use for gpio_setup_intr
  (which could obviously never fail then).

sys/bus/gpio/gpio_acpi/gpio_acpi.c
sys/bus/gpio/gpio_if.m
sys/bus/gpio/gpio_intel/gpio_cherryview.c
sys/bus/gpio/gpio_intel/gpio_intel.c
sys/bus/gpio/gpio_intel/gpio_intel_var.h

index 7042f65..0fd3608 100644 (file)
@@ -289,7 +289,6 @@ gpio_acpi_do_map_aei(device_t dev, struct acpi_event_info *info,
                    gpio->PinTableLength);
                return;
        }
-       pin = gpio->PinTable[0];
 
        /* sanity checks */
        switch (gpio->Triggering) {
@@ -310,14 +309,22 @@ gpio_acpi_do_map_aei(device_t dev, struct acpi_event_info *info,
                return;
        }
 
+       pin = gpio->PinTable[0];
+
+       if (GPIO_ALLOC_INTR(dev, pin, gpio->Triggering, gpio->Polarity,
+           gpio->PinConfig) != 0) {
+               device_printf(dev,
+                   "Failed to allocate AEI interrupt on pin %d\n", pin);
+               return;
+       }
+
        info->dev = dev;
        info->pin = pin;
        info->trigger = gpio->Triggering;
 
-       if (GPIO_ALLOC_INTR(dev, pin, gpio->Triggering, gpio->Polarity,
-           gpio->PinConfig, info, gpio_acpi_aei_handler) != 0) {
+       if (GPIO_SETUP_INTR(dev, pin, info, gpio_acpi_aei_handler) != 0) {
                device_printf(dev,
-                   "Failed to map AEI interrupt on pin %d\n", pin);
+                   "Failed to establish AEI interrupt on pin %d\n", pin);
                memset(info, 0, sizeof(*info));
        }
 }
@@ -393,8 +400,9 @@ gpio_acpi_unmap_aei(device_t dev, struct gpio_acpi_data *data)
        for (i = 0; i < data->num_aei; i++) {
                info = &data->infos[i];
                if (info->dev != NULL) {
-                       GPIO_FREE_INTR(dev, info->pin);
                        /* XXX Wait until ACPI Event handler has finished */
+                       GPIO_TEARDOWN_INTR(dev, info->pin);
+                       GPIO_FREE_INTR(dev, info->pin);
                        memset(info, 0, sizeof(*info));
                }
        }
index 4114925..7ae49ca 100644 (file)
@@ -37,7 +37,7 @@
 INTERFACE gpio;
 
 #
-# Setup GPIO interrupt handler.
+# Allocate GPIO interrupt.
 # XXX trigger, polarity and termination constants are currently used from
 #     sys/contrib/dev/acpica/source/include/acrestyp.h
 #
@@ -47,14 +47,30 @@ METHOD int alloc_intr {
        int trigger;
        int polarity;
        int termination;
+};
+
+#
+# Deallocate GPIO interrupt.
+#
+METHOD int free_intr {
+       device_t dev;
+       u_int pin;
+};
+
+#
+# Setup GPIO interrupt.
+#
+METHOD int setup_intr {
+       device_t dev;
+       u_int pin;
        void *arg;
        driver_intr_t *handler;
 };
 
 #
-# Remove GPIO interrupt handler.
+# Disable GPIO interrupt.
 #
-METHOD int free_intr {
+METHOD int teardown_intr {
        device_t dev;
        u_int pin;
 };
index afbccf9..6665773 100644 (file)
 static void    gpio_cherryview_init(struct gpio_intel_softc *sc);
 static void    gpio_cherryview_intr(void *arg);
 static int     gpio_cherryview_map_intr(struct gpio_intel_softc *sc,
-                   uint16_t pin, int trigger, int polarity, int termination,
-                   void *arg, driver_intr_t *handler);
+                   uint16_t pin, int trigger, int polarity, int termination);
 static void    gpio_cherryview_unmap_intr(struct gpio_intel_softc *sc,
                    uint16_t pin);
+static int     gpio_cherryview_establish_intr(struct gpio_intel_softc *sc,
+                   uint16_t pin, void *arg, driver_intr_t *handler);
+static void    gpio_cherryview_disestablish_intr(struct gpio_intel_softc *sc,
+                   uint16_t pin);
 static int     gpio_cherryview_read_pin(struct gpio_intel_softc *sc,
                    uint16_t pin);
 static void    gpio_cherryview_write_pin(struct gpio_intel_softc *sc,
@@ -98,6 +101,8 @@ static struct gpio_intel_fns gpio_cherryview_fns = {
        .intr = gpio_cherryview_intr,
        .map_intr = gpio_cherryview_map_intr,
        .unmap_intr = gpio_cherryview_unmap_intr,
+       .establish_intr = gpio_cherryview_establish_intr,
+       .disestablish_intr = gpio_cherryview_disestablish_intr,
        .read_pin = gpio_cherryview_read_pin,
        .write_pin = gpio_cherryview_write_pin,
 };
@@ -230,7 +235,7 @@ gpio_cherryview_intr(void *arg)
 /* XXX Add shared/exclusive argument. */
 static int
 gpio_cherryview_map_intr(struct gpio_intel_softc *sc, uint16_t pin, int trigger,
-    int polarity, int termination, void *arg, driver_intr_t *handler)
+    int polarity, int termination)
 {
        uint32_t reg, reg1, reg2;
        uint32_t intcfg, new_intcfg, gpiocfg, new_gpiocfg;
@@ -357,8 +362,8 @@ gpio_cherryview_map_intr(struct gpio_intel_softc *sc, uint16_t pin, int trigger,
        }
 
        sc->intrmaps[i].pin = pin;
-       sc->intrmaps[i].arg = arg;
-       sc->intrmaps[i].handler = handler;
+       sc->intrmaps[i].arg = NULL;
+       sc->intrmaps[i].handler = NULL;
        sc->intrmaps[i].orig_intcfg = intcfg;
        sc->intrmaps[i].orig_gpiocfg = gpiocfg;
 
@@ -367,11 +372,6 @@ gpio_cherryview_map_intr(struct gpio_intel_softc *sc, uint16_t pin, int trigger,
        else
                sc->intrmaps[i].is_level = 0;
 
-       /* unmask interrupt */
-       reg = chvgpio_read(sc, CHV_GPIO_REG_MASK);
-       reg |= (1 << i);
-       chvgpio_write(sc, CHV_GPIO_REG_MASK, reg);
-
        return (0);
 }
 
@@ -396,11 +396,6 @@ gpio_cherryview_unmap_intr(struct gpio_intel_softc *sc, uint16_t pin)
                        sc->intrmaps[i].orig_intcfg = 0;
                        sc->intrmaps[i].orig_gpiocfg = 0;
 
-                       /* mask interrupt line */
-                       reg = chvgpio_read(sc, CHV_GPIO_REG_MASK);
-                       reg &= ~(1 << i);
-                       chvgpio_write(sc, CHV_GPIO_REG_MASK, reg);
-
                        /* Restore interrupt configuration if needed */
                        reg = chvgpio_read(sc, PIN_CTL1(pin));
                        if ((reg & CHV_GPIO_CTL1_INTCFG_MASK) != intcfg) {
@@ -421,6 +416,51 @@ gpio_cherryview_unmap_intr(struct gpio_intel_softc *sc, uint16_t pin)
 }
 
 static int
+gpio_cherryview_establish_intr(struct gpio_intel_softc *sc, uint16_t pin,
+    void *arg, driver_intr_t *handler)
+{
+       uint32_t reg;
+       int i;
+
+       for (i = 0; i < 16; i++) {
+               if (sc->intrmaps[i].pin == pin) {
+                       sc->intrmaps[i].arg = arg;
+                       sc->intrmaps[i].handler = handler;
+
+                       /* clear interrupt status flag */
+                       chvgpio_write(sc, CHV_GPIO_REG_IS, (1U << i));
+
+                       /* unmask interrupt */
+                       reg = chvgpio_read(sc, CHV_GPIO_REG_MASK);
+                       reg |= (1U << i);
+                       chvgpio_write(sc, CHV_GPIO_REG_MASK, reg);
+                       return (0);
+               }
+       }
+
+       return (ENOENT);
+}
+
+static void
+gpio_cherryview_disestablish_intr(struct gpio_intel_softc *sc, uint16_t pin)
+{
+       uint32_t reg;
+       int i;
+
+       for (i = 0; i < 16; i++) {
+               if (sc->intrmaps[i].pin == pin) {
+                       /* mask interrupt line */
+                       reg = chvgpio_read(sc, CHV_GPIO_REG_MASK);
+                       reg &= ~(1U << i);
+                       chvgpio_write(sc, CHV_GPIO_REG_MASK, reg);
+
+                       sc->intrmaps[i].arg = NULL;
+                       sc->intrmaps[i].handler = NULL;
+               }
+       }
+}
+
+static int
 gpio_cherryview_read_pin(struct gpio_intel_softc *sc, uint16_t pin)
 {
        uint32_t reg;
index 2d602a9..7218e3d 100644 (file)
@@ -62,8 +62,10 @@ static int   gpio_intel_probe(device_t dev);
 static int     gpio_intel_attach(device_t dev);
 static int     gpio_intel_detach(device_t dev);
 static int     gpio_intel_alloc_intr(device_t dev, u_int pin, int trigger,
-                   int polarity, int termination, void *arg,
+                   int polarity, int termination);
+static int     gpio_intel_setup_intr(device_t dev, u_int pin, void *arg,
                    driver_intr_t *handler);
+static int     gpio_intel_teardown_intr(device_t dev, u_int pin);
 static int     gpio_intel_free_intr(device_t dev, u_int pin);
 static int     gpio_intel_read_pin(device_t dev, u_int pin);
 static void    gpio_intel_write_pin(device_t dev, u_int pin, int value);
@@ -193,7 +195,7 @@ gpio_intel_detach(device_t dev)
  */
 static int
 gpio_intel_alloc_intr(device_t dev, u_int pin, int trigger, int polarity,
-    int termination, void *arg, driver_intr_t *handler)
+    int termination)
 {
        struct gpio_intel_softc *sc = device_get_softc(dev);
        int i, ret;
@@ -207,9 +209,9 @@ gpio_intel_alloc_intr(device_t dev, u_int pin, int trigger, int polarity,
                        return (ENOMEM);
                }
                ret = sc->fns->map_intr(sc, pin, trigger, polarity,
-                   termination, arg, handler);
+                   termination);
        } else {
-               device_printf(sc->dev, "Invalid pin number %d\n", pin);
+               device_printf(sc->dev, "%s: Invalid pin %d\n", __func__, pin);
                ret = ENOENT;
        }
 
@@ -230,7 +232,7 @@ gpio_intel_free_intr(device_t dev, u_int pin)
                sc->fns->unmap_intr(sc, pin);
                ret = 0;
        } else {
-               device_printf(sc->dev, "Invalid pin number %d\n", pin);
+               device_printf(sc->dev, "%s: Invalid pin %d\n", __func__, pin);
                ret = ENOENT;
        }
 
@@ -240,6 +242,44 @@ gpio_intel_free_intr(device_t dev, u_int pin)
 }
 
 static int
+gpio_intel_setup_intr(device_t dev, u_int pin, void *arg,
+    driver_intr_t *handler)
+{
+       struct gpio_intel_softc *sc = device_get_softc(dev);
+       int ret;
+
+       lockmgr(&sc->lk, LK_EXCLUSIVE);
+       if (gpio_intel_pin_exists(sc, pin)) {
+               ret = sc->fns->establish_intr(sc, pin, arg, handler);
+       } else {
+               device_printf(sc->dev, "%s: Invalid pin %d\n", __func__, pin);
+               ret = ENOENT;
+       }
+       lockmgr(&sc->lk, LK_RELEASE);
+
+       return (ret);
+}
+
+static int
+gpio_intel_teardown_intr(device_t dev, u_int pin)
+{
+       struct gpio_intel_softc *sc = device_get_softc(dev);
+       int ret;
+
+       lockmgr(&sc->lk, LK_EXCLUSIVE);
+       if (gpio_intel_pin_exists(sc, pin)) {
+               sc->fns->disestablish_intr(sc, pin);
+               ret = 0;
+       } else {
+               device_printf(sc->dev, "%s: Invalid pin %d\n", __func__, pin);
+               ret = ENOENT;
+       }
+       lockmgr(&sc->lk, LK_RELEASE);
+
+       return (ret);
+}
+
+static int
 gpio_intel_read_pin(device_t dev, u_int pin)
 {
        struct gpio_intel_softc *sc = device_get_softc(dev);
@@ -300,6 +340,8 @@ static device_method_t gpio_intel_methods[] = {
        /* GPIO methods */
        DEVMETHOD(gpio_alloc_intr, gpio_intel_alloc_intr),
        DEVMETHOD(gpio_free_intr, gpio_intel_free_intr),
+       DEVMETHOD(gpio_setup_intr, gpio_intel_setup_intr),
+       DEVMETHOD(gpio_teardown_intr, gpio_intel_teardown_intr),
        DEVMETHOD(gpio_read_pin, gpio_intel_read_pin),
        DEVMETHOD(gpio_write_pin, gpio_intel_write_pin),
 
index 10e6b4e..3e20a4f 100644 (file)
@@ -29,10 +29,13 @@ struct gpio_intel_softc {
 
 typedef        void(*gpio_intel_init_fn)(struct gpio_intel_softc *sc);
 typedef        int(*gpio_intel_map_intr_fn)(struct gpio_intel_softc *sc,
-           uint16_t pin, int trigger, int polarity, int termination,
-           void *arg, driver_intr_t);
+           uint16_t pin, int trigger, int polarity, int termination);
 typedef        void(*gpio_intel_unmap_intr_fn)(struct gpio_intel_softc *sc,
            uint16_t pin);
+typedef        int(*gpio_intel_establish_intr_fn)(struct gpio_intel_softc *sc,
+           uint16_t pin, void *arg, driver_intr_t);
+typedef        void(*gpio_intel_disestablish_intr_fn)(struct gpio_intel_softc *sc,
+           uint16_t pin);
 typedef        void(*gpio_intel_write_pin_fn)(struct gpio_intel_softc *sc,
            uint16_t pin, int value);
 typedef        int(*gpio_intel_read_pin_fn)(struct gpio_intel_softc *sc,
@@ -43,6 +46,8 @@ struct gpio_intel_fns {
        driver_intr_t           *intr;
        gpio_intel_map_intr_fn  map_intr;
        gpio_intel_unmap_intr_fn unmap_intr;
+       gpio_intel_establish_intr_fn establish_intr;
+       gpio_intel_disestablish_intr_fn disestablish_intr;
        gpio_intel_write_pin_fn write_pin;
        gpio_intel_read_pin_fn  read_pin;
 };