The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/gpio/gpioc.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2009 Oleksandr Tymoshenko <gonzo@freebsd.org>
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/bus.h>
   35 #include <sys/conf.h>
   36 #include <sys/gpio.h>
   37 #include <sys/ioccom.h>
   38 #include <sys/filio.h>
   39 #include <sys/fcntl.h>
   40 #include <sys/sigio.h>
   41 #include <sys/signalvar.h>
   42 #include <sys/kernel.h>
   43 #include <sys/malloc.h>
   44 #include <sys/uio.h>
   45 #include <sys/poll.h>
   46 #include <sys/selinfo.h>
   47 #include <sys/module.h>
   48 
   49 #include <dev/gpio/gpiobusvar.h>
   50 
   51 #include "gpio_if.h"
   52 #include "gpiobus_if.h"
   53 
   54 #undef GPIOC_DEBUG
   55 #ifdef GPIOC_DEBUG
   56 #define dprintf printf
   57 #define ddevice_printf device_printf
   58 #else
   59 #define dprintf(x, arg...)
   60 #define ddevice_printf(dev, x, arg...)
   61 #endif
   62 
   63 struct gpioc_softc {
   64         device_t                sc_dev;         /* gpiocX dev */
   65         device_t                sc_pdev;        /* gpioX dev */
   66         struct cdev             *sc_ctl_dev;    /* controller device */
   67         int                     sc_unit;
   68         int                     sc_npins;
   69         struct gpioc_pin_intr   *sc_pin_intr;
   70 };
   71 
   72 struct gpioc_pin_intr {
   73         struct gpioc_softc                              *sc;
   74         gpio_pin_t                                      pin;
   75         bool                                            config_locked;
   76         int                                             intr_rid;
   77         struct resource                                 *intr_res;
   78         void                                            *intr_cookie;
   79         struct mtx                                      mtx;
   80         SLIST_HEAD(gpioc_privs_list, gpioc_privs)       privs;
   81 };
   82 
   83 
   84 struct gpioc_cdevpriv {
   85         struct gpioc_softc                      *sc;
   86         struct selinfo                          selinfo;
   87         bool                                    async;
   88         uint8_t                                 report_option;
   89         struct sigio                            *sigio;
   90         struct mtx                              mtx;
   91         struct gpioc_pin_event                  *events;
   92         int                                     numevents;
   93         int                                     evidx_head;
   94         int                                     evidx_tail;
   95         SLIST_HEAD(gpioc_pins_list, gpioc_pins) pins;
   96 };
   97 
   98 struct gpioc_privs {
   99         struct gpioc_cdevpriv           *priv;
  100         SLIST_ENTRY(gpioc_privs)        next;
  101 };
  102 
  103 struct gpioc_pins {
  104         struct gpioc_pin_intr   *pin;
  105         int                     eventcount;
  106         int                     firstevent;
  107         SLIST_ENTRY(gpioc_pins) next;
  108 };
  109 
  110 struct gpioc_pin_event {
  111         struct gpioc_pins       *privpin;
  112         sbintime_t              event_time;
  113         bool                    event_pin_state;
  114 };
  115 
  116 static MALLOC_DEFINE(M_GPIOC, "gpioc", "gpioc device data");
  117 
  118 static int      gpioc_allocate_pin_intr(struct gpioc_pin_intr*, uint32_t);
  119 static int      gpioc_release_pin_intr(struct gpioc_pin_intr*);
  120 static int      gpioc_attach_priv_pin(struct gpioc_cdevpriv*,
  121                     struct gpioc_pin_intr*);
  122 static int      gpioc_detach_priv_pin(struct gpioc_cdevpriv*,
  123                     struct gpioc_pin_intr*);
  124 static bool     gpioc_intr_reconfig_allowed(struct gpioc_cdevpriv*,
  125                     struct gpioc_pin_intr *intr_conf);
  126 static uint32_t gpioc_get_intr_config(struct gpioc_softc*,
  127                     struct gpioc_cdevpriv*, uint32_t pin);
  128 static int      gpioc_set_intr_config(struct gpioc_softc*,
  129                     struct gpioc_cdevpriv*, uint32_t, uint32_t);
  130 static void     gpioc_interrupt_handler(void*);
  131 
  132 static int      gpioc_kqread(struct knote*, long);
  133 static void     gpioc_kqdetach(struct knote*);
  134 
  135 static int      gpioc_probe(device_t dev);
  136 static int      gpioc_attach(device_t dev);
  137 static int      gpioc_detach(device_t dev);
  138 
  139 static void     gpioc_cdevpriv_dtor(void*);
  140 
  141 static d_open_t         gpioc_open;
  142 static d_read_t         gpioc_read;
  143 static d_ioctl_t        gpioc_ioctl;
  144 static d_poll_t         gpioc_poll;
  145 static d_kqfilter_t     gpioc_kqfilter;
  146 
  147 static struct cdevsw gpioc_cdevsw = {
  148         .d_version      = D_VERSION,
  149         .d_open         = gpioc_open,
  150         .d_read         = gpioc_read,
  151         .d_ioctl        = gpioc_ioctl,
  152         .d_poll         = gpioc_poll,
  153         .d_kqfilter     = gpioc_kqfilter,
  154         .d_name         = "gpioc",
  155 };
  156 
  157 static struct filterops gpioc_read_filterops = {
  158         .f_isfd =       true,
  159         .f_attach =     NULL,
  160         .f_detach =     gpioc_kqdetach,
  161         .f_event =      gpioc_kqread,
  162         .f_touch =      NULL
  163 };
  164 
  165 static struct gpioc_pin_event *
  166 next_head_event(struct gpioc_cdevpriv *priv)
  167 {
  168         struct gpioc_pin_event *rv;
  169 
  170         rv = &priv->events[priv->evidx_head++];
  171         if (priv->evidx_head == priv->numevents)
  172                 priv->evidx_head = 0;
  173         return (rv);
  174 }
  175 
  176 static struct gpioc_pin_event *
  177 next_tail_event(struct gpioc_cdevpriv *priv)
  178 {
  179         struct gpioc_pin_event *rv;
  180 
  181         rv = &priv->events[priv->evidx_tail++];
  182         if (priv->evidx_tail == priv->numevents)
  183                 priv->evidx_tail = 0;
  184         return (rv);
  185 }
  186 
  187 static size_t
  188 number_of_events(struct gpioc_cdevpriv *priv)
  189 {
  190         if (priv->evidx_head >= priv->evidx_tail)
  191                 return (priv->evidx_head - priv->evidx_tail);
  192         else
  193                 return (priv->numevents + priv->evidx_head - priv->evidx_tail);
  194 }
  195 
  196 static int
  197 gpioc_allocate_pin_intr(struct gpioc_pin_intr *intr_conf, uint32_t flags)
  198 {
  199         int err;
  200 
  201         intr_conf->config_locked = true;
  202         mtx_unlock(&intr_conf->mtx);
  203 
  204         intr_conf->intr_res = gpio_alloc_intr_resource(intr_conf->pin->dev,
  205             &intr_conf->intr_rid, RF_ACTIVE, intr_conf->pin, flags);
  206         if (intr_conf->intr_res == NULL) {
  207                 err = ENXIO;
  208                 goto error_exit;
  209         }
  210 
  211         err = bus_setup_intr(intr_conf->pin->dev, intr_conf->intr_res,
  212             INTR_TYPE_MISC | INTR_MPSAFE, NULL, gpioc_interrupt_handler,
  213             intr_conf, &intr_conf->intr_cookie);
  214         if (err != 0)
  215                 goto error_exit;
  216 
  217         intr_conf->pin->flags = flags;
  218 
  219 error_exit:
  220         mtx_lock(&intr_conf->mtx);
  221         intr_conf->config_locked = false;
  222         wakeup(&intr_conf->config_locked);
  223 
  224         return (err);
  225 }
  226 
  227 static int
  228 gpioc_release_pin_intr(struct gpioc_pin_intr *intr_conf)
  229 {
  230         int err;
  231 
  232         intr_conf->config_locked = true;
  233         mtx_unlock(&intr_conf->mtx);
  234 
  235         if (intr_conf->intr_cookie != NULL) {
  236                 err = bus_teardown_intr(intr_conf->pin->dev,
  237                     intr_conf->intr_res, intr_conf->intr_cookie);
  238                 if (err != 0)
  239                         goto error_exit;
  240                 else
  241                         intr_conf->intr_cookie = NULL;
  242         }
  243 
  244         if (intr_conf->intr_res != NULL) {
  245                 err = bus_release_resource(intr_conf->pin->dev, SYS_RES_IRQ,
  246                     intr_conf->intr_rid, intr_conf->intr_res);
  247                 if (err != 0)
  248                         goto error_exit;
  249                 else {
  250                         intr_conf->intr_rid = 0;
  251                         intr_conf->intr_res = NULL;
  252                 }
  253         }
  254 
  255         intr_conf->pin->flags = 0;
  256         err = 0;
  257 
  258 error_exit:
  259         mtx_lock(&intr_conf->mtx);
  260         intr_conf->config_locked = false;
  261         wakeup(&intr_conf->config_locked);
  262 
  263         return (err);
  264 }
  265 
  266 static int
  267 gpioc_attach_priv_pin(struct gpioc_cdevpriv *priv,
  268     struct gpioc_pin_intr *intr_conf)
  269 {
  270         struct gpioc_privs      *priv_link;
  271         struct gpioc_pins       *pin_link;
  272         unsigned int            consistency_a __diagused;
  273         unsigned int            consistency_b __diagused;
  274 
  275         consistency_a = 0;
  276         consistency_b = 0;
  277         mtx_assert(&intr_conf->mtx, MA_OWNED);
  278         mtx_lock(&priv->mtx);
  279         SLIST_FOREACH(priv_link, &intr_conf->privs, next) {
  280                 if (priv_link->priv == priv)
  281                         consistency_a++;
  282         }
  283         KASSERT(consistency_a <= 1,
  284             ("inconsistent links between pin config and cdevpriv"));
  285         SLIST_FOREACH(pin_link, &priv->pins, next) {
  286                 if (pin_link->pin == intr_conf)
  287                         consistency_b++;
  288         }
  289         KASSERT(consistency_a == consistency_b,
  290             ("inconsistent links between pin config and cdevpriv"));
  291         if (consistency_a == 1 && consistency_b == 1) {
  292                 mtx_unlock(&priv->mtx);
  293                 return (EEXIST);
  294         }
  295         priv_link = malloc(sizeof(struct gpioc_privs), M_GPIOC,
  296             M_NOWAIT | M_ZERO);
  297         if (priv_link == NULL)
  298         {
  299                 mtx_unlock(&priv->mtx);
  300                 return (ENOMEM);
  301         }
  302         pin_link = malloc(sizeof(struct gpioc_pins), M_GPIOC,
  303             M_NOWAIT | M_ZERO);
  304         if (pin_link == NULL) {
  305                 mtx_unlock(&priv->mtx);
  306                 return (ENOMEM);
  307         }
  308         priv_link->priv = priv;
  309         pin_link->pin = intr_conf;
  310         SLIST_INSERT_HEAD(&intr_conf->privs, priv_link, next);
  311         SLIST_INSERT_HEAD(&priv->pins, pin_link, next);
  312         mtx_unlock(&priv->mtx);
  313 
  314         return (0);
  315 }
  316 
  317 static int
  318 gpioc_detach_priv_pin(struct gpioc_cdevpriv *priv,
  319     struct gpioc_pin_intr *intr_conf)
  320 {
  321         struct gpioc_privs      *priv_link, *priv_link_temp;
  322         struct gpioc_pins       *pin_link, *pin_link_temp;
  323         unsigned int            consistency_a __diagused;
  324         unsigned int            consistency_b __diagused;
  325 
  326         consistency_a = 0;
  327         consistency_b = 0;
  328         mtx_assert(&intr_conf->mtx, MA_OWNED);
  329         mtx_lock(&priv->mtx);
  330         SLIST_FOREACH_SAFE(priv_link, &intr_conf->privs, next, priv_link_temp) {
  331                 if (priv_link->priv == priv) {
  332                         SLIST_REMOVE(&intr_conf->privs, priv_link, gpioc_privs,
  333                             next);
  334                         free(priv_link, M_GPIOC);
  335                         consistency_a++;
  336                 }
  337         }
  338         KASSERT(consistency_a <= 1,
  339             ("inconsistent links between pin config and cdevpriv"));
  340         SLIST_FOREACH_SAFE(pin_link, &priv->pins, next, pin_link_temp) {
  341                 if (pin_link->pin == intr_conf) {
  342                         /*
  343                          * If the pin we're removing has events in the priv's
  344                          * event fifo, we can't leave dangling pointers from
  345                          * those events to the gpioc_pins struct we're about to
  346                          * free.  We also can't remove random items and leave
  347                          * holes in the events fifo, so just empty it out.
  348                          */
  349                         if (pin_link->eventcount > 0) {
  350                                 priv->evidx_head = priv->evidx_tail = 0;
  351                         }
  352                         SLIST_REMOVE(&priv->pins, pin_link, gpioc_pins, next);
  353                         free(pin_link, M_GPIOC);
  354                         consistency_b++;
  355                 }
  356         }
  357         KASSERT(consistency_a == consistency_b,
  358             ("inconsistent links between pin config and cdevpriv"));
  359         mtx_unlock(&priv->mtx);
  360 
  361         return (0);
  362 }
  363 
  364 static bool
  365 gpioc_intr_reconfig_allowed(struct gpioc_cdevpriv *priv,
  366     struct gpioc_pin_intr *intr_conf)
  367 {
  368         struct gpioc_privs      *priv_link;
  369 
  370         mtx_assert(&intr_conf->mtx, MA_OWNED);
  371 
  372         if (SLIST_EMPTY(&intr_conf->privs))
  373                 return (true);
  374 
  375         SLIST_FOREACH(priv_link, &intr_conf->privs, next) {
  376                 if (priv_link->priv != priv)
  377                         return (false);
  378         }
  379 
  380         return (true);
  381 }
  382 
  383 
  384 static uint32_t
  385 gpioc_get_intr_config(struct gpioc_softc *sc, struct gpioc_cdevpriv *priv,
  386     uint32_t pin)
  387 {
  388         struct gpioc_pin_intr   *intr_conf = &sc->sc_pin_intr[pin];
  389         struct gpioc_privs      *priv_link;
  390         uint32_t                flags;
  391 
  392         flags = intr_conf->pin->flags;
  393 
  394         if (flags == 0)
  395                 return (0);
  396 
  397         mtx_lock(&intr_conf->mtx);
  398         SLIST_FOREACH(priv_link, &intr_conf->privs, next) {
  399                 if (priv_link->priv == priv) {
  400                         flags |= GPIO_INTR_ATTACHED;
  401                         break;
  402                 }
  403         }
  404         mtx_unlock(&intr_conf->mtx);
  405 
  406         return (flags);
  407 }
  408 
  409 static int
  410 gpioc_set_intr_config(struct gpioc_softc *sc, struct gpioc_cdevpriv *priv,
  411     uint32_t pin, uint32_t flags)
  412 {
  413         struct gpioc_pin_intr *intr_conf = &sc->sc_pin_intr[pin];
  414         int res;
  415 
  416         res = 0;
  417         if (intr_conf->pin->flags == 0 && flags == 0) {
  418                 /* No interrupt configured and none requested: Do nothing. */
  419                 return (0);
  420         }
  421         mtx_lock(&intr_conf->mtx);
  422         while (intr_conf->config_locked == true)
  423                 mtx_sleep(&intr_conf->config_locked, &intr_conf->mtx, 0,
  424                     "gpicfg", 0);
  425         if (intr_conf->pin->flags == 0 && flags != 0) {
  426                 /*
  427                  * No interrupt is configured, but one is requested: Allocate
  428                  * and setup interrupt on the according pin.
  429                  */
  430                 res = gpioc_allocate_pin_intr(intr_conf, flags);
  431                 if (res == 0)
  432                         res = gpioc_attach_priv_pin(priv, intr_conf);
  433                 if (res == EEXIST)
  434                         res = 0;
  435         } else if (intr_conf->pin->flags == flags) {
  436                 /*
  437                  * Same interrupt requested as already configured: Attach the
  438                  * cdevpriv to the corresponding pin.
  439                  */
  440                 res = gpioc_attach_priv_pin(priv, intr_conf);
  441                 if (res == EEXIST)
  442                         res = 0;
  443         } else if (intr_conf->pin->flags != 0 && flags == 0) {
  444                 /*
  445                  * Interrupt configured, but none requested: Teardown and
  446                  * release the pin when no other cdevpriv is attached. Otherwise
  447                  * just detach pin and cdevpriv from each other.
  448                  */
  449                 if (gpioc_intr_reconfig_allowed(priv, intr_conf)) {
  450                         res = gpioc_release_pin_intr(intr_conf);
  451                 }
  452                 if (res == 0)
  453                         res = gpioc_detach_priv_pin(priv, intr_conf);
  454         } else {
  455                 /*
  456                  * Other flag requested than configured: Reconfigure when no
  457                  * other cdevpriv is are attached to the pin.
  458                  */
  459                 if (!gpioc_intr_reconfig_allowed(priv, intr_conf))
  460                         res = EBUSY;
  461                 else {
  462                         res = gpioc_release_pin_intr(intr_conf);
  463                         if (res == 0)
  464                                 res = gpioc_allocate_pin_intr(intr_conf, flags);
  465                         if (res == 0)
  466                                 res = gpioc_attach_priv_pin(priv, intr_conf);
  467                         if (res == EEXIST)
  468                                 res = 0;
  469                 }
  470         }
  471         mtx_unlock(&intr_conf->mtx);
  472 
  473         return (res);
  474 }
  475 
  476 static void
  477 gpioc_interrupt_handler(void *arg)
  478 {
  479         struct gpioc_pin_intr *intr_conf;
  480         struct gpioc_privs *privs;
  481         struct gpioc_softc *sc;
  482         sbintime_t evtime;
  483         uint32_t pin_state;
  484 
  485         intr_conf = arg;
  486         sc = intr_conf->sc;
  487 
  488         /* Capture time and pin state first. */
  489         evtime = sbinuptime();
  490         if (intr_conf->pin->flags & GPIO_INTR_EDGE_BOTH)
  491                 GPIO_PIN_GET(sc->sc_pdev, intr_conf->pin->pin, &pin_state);
  492         else if (intr_conf->pin->flags & GPIO_INTR_EDGE_RISING)
  493                 pin_state = true;
  494         else
  495                 pin_state = false;
  496 
  497         mtx_lock(&intr_conf->mtx);
  498 
  499         if (intr_conf->config_locked == true) {
  500                 ddevice_printf(sc->sc_dev, "Interrupt configuration in "
  501                     "progress. Discarding interrupt on pin %d.\n",
  502                     intr_conf->pin->pin);
  503                 mtx_unlock(&intr_conf->mtx);
  504                 return;
  505         }
  506 
  507         if (SLIST_EMPTY(&intr_conf->privs)) {
  508                 ddevice_printf(sc->sc_dev, "No file descriptor associated with "
  509                     "occurred interrupt on pin %d.\n", intr_conf->pin->pin);
  510                 mtx_unlock(&intr_conf->mtx);
  511                 return;
  512         }
  513 
  514         SLIST_FOREACH(privs, &intr_conf->privs, next) {
  515                 struct gpioc_cdevpriv *priv = privs->priv;
  516                 struct gpioc_pins *privpin;
  517                 struct gpioc_pin_event *event;
  518                 mtx_lock(&priv->mtx);
  519                 SLIST_FOREACH(privpin, &priv->pins, next) {
  520                         if (privpin->pin == intr_conf)
  521                                 break;
  522                 }
  523                 if (privpin == NULL) {
  524                         /* Should be impossible. */
  525                         ddevice_printf(sc->sc_dev, "Cannot find privpin\n");
  526                         mtx_unlock(&priv->mtx);
  527                         continue;
  528                 }
  529 
  530                 if (priv->report_option == GPIO_EVENT_REPORT_DETAIL) {
  531                         event = next_head_event(priv);
  532                         /* If head is overtaking tail, advance tail. */
  533                         if (priv->evidx_head == priv->evidx_tail)
  534                                 next_tail_event(priv);
  535                 } else {
  536                         if (privpin->eventcount > 0)
  537                                 event = &priv->events[privpin->firstevent + 1];
  538                         else {
  539                                 privpin->firstevent = priv->evidx_head;
  540                                 event = next_head_event(priv);
  541                                 event->privpin = privpin;
  542                                 event->event_time = evtime;
  543                                 event->event_pin_state = pin_state;
  544                                 event = next_head_event(priv);
  545                         }
  546                         ++privpin->eventcount;
  547                 }
  548                 event->privpin = privpin;
  549                 event->event_time = evtime;
  550                 event->event_pin_state = pin_state;
  551                 wakeup(priv);
  552                 selwakeup(&priv->selinfo);
  553                 KNOTE_LOCKED(&priv->selinfo.si_note, 0);
  554                 if (priv->async == true && priv->sigio != NULL)
  555                         pgsigio(&priv->sigio, SIGIO, 0);
  556                 mtx_unlock(&priv->mtx);
  557         }
  558 
  559         mtx_unlock(&intr_conf->mtx);
  560 }
  561 
  562 static int
  563 gpioc_probe(device_t dev)
  564 {
  565         device_set_desc(dev, "GPIO controller");
  566         return (0);
  567 }
  568 
  569 static int
  570 gpioc_attach(device_t dev)
  571 {
  572         int err;
  573         struct gpioc_softc *sc;
  574         struct make_dev_args devargs;
  575 
  576         sc = device_get_softc(dev);
  577         sc->sc_dev = dev;
  578         sc->sc_pdev = device_get_parent(dev);
  579         sc->sc_unit = device_get_unit(dev);
  580 
  581         err = GPIO_PIN_MAX(sc->sc_pdev, &sc->sc_npins);
  582         sc->sc_npins++; /* Number of pins is one more than max pin number. */
  583         if (err != 0)
  584                 return (err);
  585         sc->sc_pin_intr = malloc(sizeof(struct gpioc_pin_intr) * sc->sc_npins,
  586             M_GPIOC, M_WAITOK | M_ZERO);
  587         for (int i = 0; i < sc->sc_npins; i++) {
  588                 sc->sc_pin_intr[i].pin = malloc(sizeof(struct gpiobus_pin),
  589                     M_GPIOC, M_WAITOK | M_ZERO);
  590                 sc->sc_pin_intr[i].sc = sc;
  591                 sc->sc_pin_intr[i].pin->pin = i;
  592                 sc->sc_pin_intr[i].pin->dev = sc->sc_pdev;
  593                 mtx_init(&sc->sc_pin_intr[i].mtx, "gpioc pin", NULL, MTX_DEF);
  594                 SLIST_INIT(&sc->sc_pin_intr[i].privs);
  595         }
  596 
  597         make_dev_args_init(&devargs);
  598         devargs.mda_devsw = &gpioc_cdevsw;
  599         devargs.mda_uid = UID_ROOT;
  600         devargs.mda_gid = GID_WHEEL;
  601         devargs.mda_mode = 0600;
  602         devargs.mda_si_drv1 = sc;
  603         err = make_dev_s(&devargs, &sc->sc_ctl_dev, "gpioc%d", sc->sc_unit);
  604         if (err != 0) {
  605                 device_printf(dev, "Failed to create gpioc%d", sc->sc_unit);
  606                 return (ENXIO);
  607         }
  608 
  609         return (0);
  610 }
  611 
  612 static int
  613 gpioc_detach(device_t dev)
  614 {
  615         struct gpioc_softc *sc = device_get_softc(dev);
  616         int err;
  617 
  618         if (sc->sc_ctl_dev)
  619                 destroy_dev(sc->sc_ctl_dev);
  620 
  621         for (int i = 0; i < sc->sc_npins; i++) {
  622                 mtx_destroy(&sc->sc_pin_intr[i].mtx);
  623                 free(sc->sc_pin_intr[i].pin, M_GPIOC);
  624         }
  625         free(sc->sc_pin_intr, M_GPIOC);
  626 
  627         if ((err = bus_generic_detach(dev)) != 0)
  628                 return (err);
  629 
  630         return (0);
  631 }
  632 
  633 static void
  634 gpioc_cdevpriv_dtor(void *data)
  635 {
  636         struct gpioc_cdevpriv   *priv;
  637         struct gpioc_privs      *priv_link, *priv_link_temp;
  638         struct gpioc_pins       *pin_link, *pin_link_temp;
  639         unsigned int            consistency __diagused;
  640 
  641         priv = data;
  642 
  643         SLIST_FOREACH_SAFE(pin_link, &priv->pins, next, pin_link_temp) {
  644                 consistency = 0;
  645                 mtx_lock(&pin_link->pin->mtx);
  646                 while (pin_link->pin->config_locked == true)
  647                         mtx_sleep(&pin_link->pin->config_locked,
  648                             &pin_link->pin->mtx, 0, "gpicfg", 0);
  649                 SLIST_FOREACH_SAFE(priv_link, &pin_link->pin->privs, next,
  650                     priv_link_temp) {
  651                         if (priv_link->priv == priv) {
  652                                 SLIST_REMOVE(&pin_link->pin->privs, priv_link,
  653                                     gpioc_privs, next);
  654                                 free(priv_link, M_GPIOC);
  655                                 consistency++;
  656                         }
  657                 }
  658                 KASSERT(consistency == 1,
  659                     ("inconsistent links between pin config and cdevpriv"));
  660                 if (gpioc_intr_reconfig_allowed(priv, pin_link->pin)) {
  661                         gpioc_release_pin_intr(pin_link->pin);
  662                 }
  663                 mtx_unlock(&pin_link->pin->mtx);
  664                 SLIST_REMOVE(&priv->pins, pin_link, gpioc_pins, next);
  665                 free(pin_link, M_GPIOC);
  666         }
  667 
  668         wakeup(&priv);
  669         knlist_clear(&priv->selinfo.si_note, 0);
  670         seldrain(&priv->selinfo);
  671         knlist_destroy(&priv->selinfo.si_note);
  672         funsetown(&priv->sigio);
  673 
  674         mtx_destroy(&priv->mtx);
  675         free(priv->events, M_GPIOC);
  676         free(data, M_GPIOC);
  677 }
  678 
  679 static int
  680 gpioc_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
  681 {
  682         struct gpioc_cdevpriv *priv;
  683         int err;
  684 
  685         priv = malloc(sizeof(*priv), M_GPIOC, M_WAITOK | M_ZERO);
  686         priv->sc = dev->si_drv1;
  687         priv->report_option = GPIO_EVENT_REPORT_DETAIL;
  688         err = devfs_set_cdevpriv(priv, gpioc_cdevpriv_dtor);
  689         if (err != 0) {
  690                 gpioc_cdevpriv_dtor(priv);
  691                 return (err);
  692         }
  693         mtx_init(&priv->mtx, "gpioc priv", NULL, MTX_DEF);
  694         knlist_init_mtx(&priv->selinfo.si_note, &priv->mtx);
  695 
  696         /*
  697          * Allocate a circular buffer for events.  The scheme we use for summary
  698          * reporting assumes there will always be a pair of events available to
  699          * record the first/last events on any pin, so we allocate 2 * npins.
  700          * Even though we actually default to detailed event reporting, 2 *
  701          * npins isn't a horrible fifo size for that either.
  702          */
  703         priv->numevents = priv->sc->sc_npins * 2;
  704         priv->events = malloc(priv->numevents * sizeof(struct gpio_event_detail),
  705             M_GPIOC, M_WAITOK | M_ZERO);
  706 
  707         return (0);
  708 }
  709 
  710 static int
  711 gpioc_read(struct cdev *dev, struct uio *uio, int ioflag)
  712 {
  713         struct gpioc_cdevpriv *priv;
  714         struct gpioc_pin_event *event;
  715         union {
  716                 struct gpio_event_summary sum;
  717                 struct gpio_event_detail  evt;
  718                 uint8_t                   data[1];
  719         } recbuf;
  720         size_t recsize;
  721         int err;
  722 
  723         if ((err = devfs_get_cdevpriv((void **)&priv)) != 0)
  724                 return (err);
  725 
  726         if (priv->report_option == GPIO_EVENT_REPORT_SUMMARY)
  727                 recsize = sizeof(struct gpio_event_summary);
  728         else
  729                 recsize = sizeof(struct gpio_event_detail);
  730 
  731         if (uio->uio_resid < recsize)
  732                 return (EINVAL);
  733 
  734         mtx_lock(&priv->mtx);
  735         while (priv->evidx_head == priv->evidx_tail) {
  736                 if (SLIST_EMPTY(&priv->pins)) {
  737                         err = ENXIO;
  738                         break;
  739                 } else if (ioflag & O_NONBLOCK) {
  740                         err = EWOULDBLOCK;
  741                         break;
  742                 } else {
  743                         err = mtx_sleep(priv, &priv->mtx, PCATCH, "gpintr", 0);
  744                         if (err != 0)
  745                                 break;
  746                 }
  747         }
  748 
  749         while (err == 0 && uio->uio_resid >= recsize &&
  750            priv->evidx_tail != priv->evidx_head) {
  751                 event = next_tail_event(priv);
  752                 if (priv->report_option == GPIO_EVENT_REPORT_SUMMARY) {
  753                         recbuf.sum.gp_first_time = event->event_time;
  754                         recbuf.sum.gp_pin = event->privpin->pin->pin->pin;
  755                         recbuf.sum.gp_count = event->privpin->eventcount;
  756                         recbuf.sum.gp_first_state = event->event_pin_state;
  757                         event = next_tail_event(priv);
  758                         recbuf.sum.gp_last_time = event->event_time;
  759                         recbuf.sum.gp_last_state = event->event_pin_state;
  760                         event->privpin->eventcount = 0;
  761                         event->privpin->firstevent = 0;
  762                 } else {
  763                         recbuf.evt.gp_time = event->event_time;
  764                         recbuf.evt.gp_pin = event->privpin->pin->pin->pin;
  765                         recbuf.evt.gp_pinstate = event->event_pin_state;
  766                 }
  767                 mtx_unlock(&priv->mtx);
  768                 err = uiomove(recbuf.data, recsize, uio);
  769                 mtx_lock(&priv->mtx);
  770         }
  771         mtx_unlock(&priv->mtx);
  772         return (err);
  773 }
  774 
  775 static int 
  776 gpioc_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag, 
  777     struct thread *td)
  778 {
  779         device_t bus;
  780         int max_pin, res;
  781         struct gpioc_softc *sc = cdev->si_drv1;
  782         struct gpioc_cdevpriv *priv;
  783         struct gpio_pin pin;
  784         struct gpio_req req;
  785         struct gpio_access_32 *a32;
  786         struct gpio_config_32 *c32;
  787         struct gpio_event_config *evcfg;
  788         uint32_t caps, intrflags;
  789 
  790         bus = GPIO_GET_BUS(sc->sc_pdev);
  791         if (bus == NULL)
  792                 return (EINVAL);
  793         switch (cmd) {
  794         case GPIOMAXPIN:
  795                 max_pin = -1;
  796                 res = GPIO_PIN_MAX(sc->sc_pdev, &max_pin);
  797                 bcopy(&max_pin, arg, sizeof(max_pin));
  798                 break;
  799         case GPIOGETCONFIG:
  800                 bcopy(arg, &pin, sizeof(pin));
  801                 dprintf("get config pin %d\n", pin.gp_pin);
  802                 res = GPIO_PIN_GETFLAGS(sc->sc_pdev, pin.gp_pin,
  803                     &pin.gp_flags);
  804                 /* Fail early */
  805                 if (res)
  806                         break;
  807                 res = devfs_get_cdevpriv((void **)&priv);
  808                 if (res)
  809                         break;
  810                 pin.gp_flags |= gpioc_get_intr_config(sc, priv,
  811                     pin.gp_pin);
  812                 GPIO_PIN_GETCAPS(sc->sc_pdev, pin.gp_pin, &pin.gp_caps);
  813                 GPIOBUS_PIN_GETNAME(bus, pin.gp_pin, pin.gp_name);
  814                 bcopy(&pin, arg, sizeof(pin));
  815                 break;
  816         case GPIOSETCONFIG:
  817                 bcopy(arg, &pin, sizeof(pin));
  818                 dprintf("set config pin %d\n", pin.gp_pin);
  819                 res = devfs_get_cdevpriv((void **)&priv);
  820                 if (res != 0)
  821                         break;
  822                 res = GPIO_PIN_GETCAPS(sc->sc_pdev, pin.gp_pin, &caps);
  823                 if (res != 0)
  824                         break;
  825                 res = gpio_check_flags(caps, pin.gp_flags);
  826                 if (res != 0)
  827                         break;
  828                 intrflags = pin.gp_flags & GPIO_INTR_MASK;
  829                 /*
  830                  * We can do only edge interrupts, and only if the
  831                  * hardware supports that interrupt type on that pin.
  832                  */
  833                 switch (intrflags) {
  834                 case GPIO_INTR_NONE:
  835                         break;
  836                 case GPIO_INTR_EDGE_RISING:
  837                 case GPIO_INTR_EDGE_FALLING:
  838                 case GPIO_INTR_EDGE_BOTH:
  839                         if ((intrflags & caps) == 0)
  840                                 res = EOPNOTSUPP;
  841                         break;
  842                 default:
  843                         res = EINVAL;
  844                         break;
  845                 }
  846                 if (res != 0)
  847                         break;
  848                 res = GPIO_PIN_SETFLAGS(sc->sc_pdev, pin.gp_pin,
  849                     (pin.gp_flags & ~GPIO_INTR_MASK));
  850                 if (res != 0)
  851                         break;
  852                 res = gpioc_set_intr_config(sc, priv, pin.gp_pin,
  853                     intrflags);
  854                 break;
  855         case GPIOGET:
  856                 bcopy(arg, &req, sizeof(req));
  857                 res = GPIO_PIN_GET(sc->sc_pdev, req.gp_pin,
  858                     &req.gp_value);
  859                 dprintf("read pin %d -> %d\n", 
  860                     req.gp_pin, req.gp_value);
  861                 bcopy(&req, arg, sizeof(req));
  862                 break;
  863         case GPIOSET:
  864                 bcopy(arg, &req, sizeof(req));
  865                 res = GPIO_PIN_SET(sc->sc_pdev, req.gp_pin, 
  866                     req.gp_value);
  867                 dprintf("write pin %d -> %d\n", 
  868                     req.gp_pin, req.gp_value);
  869                 break;
  870         case GPIOTOGGLE:
  871                 bcopy(arg, &req, sizeof(req));
  872                 dprintf("toggle pin %d\n", 
  873                     req.gp_pin);
  874                 res = GPIO_PIN_TOGGLE(sc->sc_pdev, req.gp_pin);
  875                 break;
  876         case GPIOSETNAME:
  877                 bcopy(arg, &pin, sizeof(pin));
  878                 dprintf("set name on pin %d\n", pin.gp_pin);
  879                 res = GPIOBUS_PIN_SETNAME(bus, pin.gp_pin,
  880                     pin.gp_name);
  881                 break;
  882         case GPIOACCESS32:
  883                 a32 = (struct gpio_access_32 *)arg;
  884                 res = GPIO_PIN_ACCESS_32(sc->sc_pdev, a32->first_pin,
  885                     a32->clear_pins, a32->change_pins, &a32->orig_pins);
  886                 break;
  887         case GPIOCONFIG32:
  888                 c32 = (struct gpio_config_32 *)arg;
  889                 res = GPIO_PIN_CONFIG_32(sc->sc_pdev, c32->first_pin,
  890                     c32->num_pins, c32->pin_flags);
  891                 break;
  892         case GPIOCONFIGEVENTS:
  893                 evcfg = (struct gpio_event_config *)arg;
  894                 res = devfs_get_cdevpriv((void **)&priv);
  895                 if (res != 0)
  896                         break;
  897                 /* If any pins have been configured, changes aren't allowed. */
  898                 if (!SLIST_EMPTY(&priv->pins)) {
  899                         res = EINVAL;
  900                         break;
  901                 }
  902                 if (evcfg->gp_report_type != GPIO_EVENT_REPORT_DETAIL &&
  903                     evcfg->gp_report_type != GPIO_EVENT_REPORT_SUMMARY) {
  904                         res = EINVAL;
  905                         break;
  906                 }
  907                 priv->report_option = evcfg->gp_report_type;
  908                 /* Reallocate the events buffer if the user wants it bigger. */
  909                 if (priv->report_option == GPIO_EVENT_REPORT_DETAIL &&
  910                     priv->numevents < evcfg->gp_fifo_size) {
  911                         free(priv->events, M_GPIOC);
  912                         priv->numevents = evcfg->gp_fifo_size;
  913                         priv->events = malloc(priv->numevents *
  914                             sizeof(struct gpio_event_detail), M_GPIOC,
  915                             M_WAITOK | M_ZERO);
  916                         priv->evidx_head = priv->evidx_tail = 0;
  917                 }
  918                 break;
  919         case FIONBIO:
  920                 /*
  921                  * This dummy handler is necessary to prevent fcntl()
  922                  * from failing. The actual handling of non-blocking IO
  923                  * is done using the O_NONBLOCK ioflag passed to the
  924                  * read() syscall.
  925                  */
  926                 res = 0;
  927                 break;
  928         case FIOASYNC:
  929                 res = devfs_get_cdevpriv((void **)&priv);
  930                 if (res == 0) {
  931                         if (*(int *)arg == FASYNC)
  932                                 priv->async = true;
  933                         else
  934                                 priv->async = false;
  935                 }
  936                 break;
  937         case FIOGETOWN:
  938                 res = devfs_get_cdevpriv((void **)&priv);
  939                 if (res == 0)
  940                         *(int *)arg = fgetown(&priv->sigio);
  941                 break;
  942         case FIOSETOWN:
  943                 res = devfs_get_cdevpriv((void **)&priv);
  944                 if (res == 0)
  945                         res = fsetown(*(int *)arg, &priv->sigio);
  946                 break;
  947         default:
  948                 return (ENOTTY);
  949                 break;
  950         }
  951 
  952         return (res);
  953 }
  954 
  955 static int
  956 gpioc_poll(struct cdev *dev, int events, struct thread *td)
  957 {
  958         struct gpioc_cdevpriv *priv;
  959         int err;
  960         int revents;
  961 
  962         revents = 0;
  963 
  964         err = devfs_get_cdevpriv((void **)&priv);
  965         if (err != 0) {
  966                 revents = POLLERR;
  967                 return (revents);
  968         }
  969 
  970         if (SLIST_EMPTY(&priv->pins)) {
  971                 revents = POLLHUP;
  972                 return (revents);
  973         }
  974 
  975         if (events & (POLLIN | POLLRDNORM)) {
  976                 if (priv->evidx_head != priv->evidx_tail)
  977                         revents |= events & (POLLIN | POLLRDNORM);
  978                 else
  979                         selrecord(td, &priv->selinfo);
  980         }
  981 
  982         return (revents);
  983 }
  984 
  985 static int
  986 gpioc_kqfilter(struct cdev *dev, struct knote *kn)
  987 {
  988         struct gpioc_cdevpriv *priv;
  989         struct knlist *knlist;
  990         int err;
  991 
  992         err = devfs_get_cdevpriv((void **)&priv);
  993         if (err != 0)
  994                 return err;
  995 
  996         if (SLIST_EMPTY(&priv->pins))
  997                 return (ENXIO);
  998 
  999         switch(kn->kn_filter) {
 1000         case EVFILT_READ:
 1001                 kn->kn_fop = &gpioc_read_filterops;
 1002                 kn->kn_hook = (void *)priv;
 1003                 break;
 1004         default:
 1005                 return (EOPNOTSUPP);
 1006         }
 1007 
 1008         knlist = &priv->selinfo.si_note;
 1009         knlist_add(knlist, kn, 0);
 1010 
 1011         return (0);
 1012 }
 1013 
 1014 static int
 1015 gpioc_kqread(struct knote *kn, long hint)
 1016 {
 1017         struct gpioc_cdevpriv *priv = kn->kn_hook;
 1018         size_t recsize;
 1019 
 1020 
 1021         if (SLIST_EMPTY(&priv->pins)) {
 1022                 kn->kn_flags |= EV_EOF;
 1023                 return (1);
 1024         } else {
 1025                 if (priv->evidx_head != priv->evidx_tail) {
 1026                         if (priv->report_option == GPIO_EVENT_REPORT_SUMMARY)
 1027                                 recsize = sizeof(struct gpio_event_summary);
 1028                         else
 1029                                 recsize = sizeof(struct gpio_event_detail);
 1030                         kn->kn_data = recsize * number_of_events(priv);
 1031                         return (1);
 1032                 }
 1033         }
 1034         return (0);
 1035 }
 1036 
 1037 static void
 1038 gpioc_kqdetach(struct knote *kn)
 1039 {
 1040         struct gpioc_cdevpriv *priv = kn->kn_hook;
 1041         struct knlist *knlist = &priv->selinfo.si_note;
 1042 
 1043         knlist_remove(knlist, kn, 0);
 1044 }
 1045 
 1046 static device_method_t gpioc_methods[] = {
 1047         /* Device interface */
 1048         DEVMETHOD(device_probe,         gpioc_probe),
 1049         DEVMETHOD(device_attach,        gpioc_attach),
 1050         DEVMETHOD(device_detach,        gpioc_detach),
 1051         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
 1052         DEVMETHOD(device_suspend,       bus_generic_suspend),
 1053         DEVMETHOD(device_resume,        bus_generic_resume),
 1054 
 1055         DEVMETHOD_END
 1056 };
 1057 
 1058 driver_t gpioc_driver = {
 1059         "gpioc",
 1060         gpioc_methods,
 1061         sizeof(struct gpioc_softc)
 1062 };
 1063 
 1064 DRIVER_MODULE(gpioc, gpio, gpioc_driver, 0, 0);
 1065 MODULE_VERSION(gpioc, 1);

Cache object: e69fc4f0af384f9bc22b2c14e5bb897c


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.