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/gpiobus.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  * Copyright (c) 2009 Oleksandr Tymoshenko <gonzo@freebsd.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD: releng/9.0/sys/dev/gpio/gpiobus.c 215142 2010-11-11 20:18:33Z thompsa $");
   29 
   30 #include <sys/param.h>
   31 #include <sys/systm.h>
   32 #include <sys/malloc.h>
   33 #include <sys/module.h>
   34 #include <sys/kernel.h>
   35 #include <sys/queue.h>
   36 #include <sys/sysctl.h>
   37 #include <sys/types.h>
   38 
   39 #include <sys/bus.h>
   40 #include <machine/bus.h>
   41 #include <sys/rman.h>
   42 #include <machine/resource.h>
   43 
   44 #include <sys/gpio.h>
   45 #include <dev/gpio/gpiobusvar.h>
   46 #include "gpio_if.h"
   47 #include "gpiobus_if.h"
   48 
   49 static void gpiobus_print_pins(struct gpiobus_ivar *);
   50 static int gpiobus_parse_pins(struct gpiobus_softc *, device_t, int);
   51 static int gpiobus_probe(device_t);
   52 static int gpiobus_attach(device_t);
   53 static int gpiobus_detach(device_t);
   54 static int gpiobus_suspend(device_t);
   55 static int gpiobus_resume(device_t);
   56 static int gpiobus_print_child(device_t, device_t);
   57 static int gpiobus_child_location_str(device_t, device_t, char *, size_t);
   58 static int gpiobus_child_pnpinfo_str(device_t, device_t, char *, size_t);
   59 static device_t gpiobus_add_child(device_t, u_int, const char *, int);
   60 static void gpiobus_hinted_child(device_t, const char *, int);
   61 
   62 /*
   63  * GPIOBUS interface
   64  */
   65 static void gpiobus_lock_bus(device_t);
   66 static void gpiobus_unlock_bus(device_t);
   67 static void gpiobus_acquire_bus(device_t, device_t);
   68 static void gpiobus_release_bus(device_t, device_t);
   69 static int gpiobus_pin_setflags(device_t, device_t, uint32_t, uint32_t);
   70 static int gpiobus_pin_getflags(device_t, device_t, uint32_t, uint32_t*);
   71 static int gpiobus_pin_getcaps(device_t, device_t, uint32_t, uint32_t*);
   72 static int gpiobus_pin_set(device_t, device_t, uint32_t, unsigned int);
   73 static int gpiobus_pin_get(device_t, device_t, uint32_t, unsigned int*);
   74 static int gpiobus_pin_toggle(device_t, device_t, uint32_t);
   75 
   76 #define GPIOBUS_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
   77 #define GPIOBUS_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
   78 #define GPIOBUS_LOCK_INIT(_sc) \
   79         mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \
   80             "gpiobus", MTX_DEF)
   81 #define GPIOBUS_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx);
   82 #define GPIOBUS_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED);
   83 #define GPIOBUS_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
   84 
   85 
   86 static void
   87 gpiobus_print_pins(struct gpiobus_ivar *devi)
   88 {
   89         int range_start, range_stop, need_coma;
   90         int i;
   91 
   92         if (devi->npins == 0)
   93                 return;
   94 
   95         need_coma = 0;
   96         range_start = range_stop = devi->pins[0];
   97         for (i = 1; i < devi->npins; i++) {
   98                 if (devi->pins[i] != (range_stop + 1)) {
   99                         if (need_coma)
  100                                 printf(",");
  101                         if (range_start != range_stop)
  102                                 printf("%d-%d", range_start, range_stop);
  103                         else
  104                                 printf("%d", range_start);
  105 
  106                         range_start = range_stop = devi->pins[i];
  107                         need_coma = 1;
  108                 }
  109                 else
  110                         range_stop++;
  111         }
  112 
  113         if (need_coma)
  114                 printf(",");
  115         if (range_start != range_stop)
  116                 printf("%d-%d", range_start, range_stop);
  117         else
  118                 printf("%d", range_start);
  119 }
  120 
  121 static int
  122 gpiobus_parse_pins(struct gpiobus_softc *sc, device_t child, int mask)
  123 {
  124         struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
  125         int i, npins;
  126 
  127         npins = 0;
  128         for (i = 0; i < 32; i++) {
  129                 if (mask & (1 << i))
  130                         npins++;
  131         }
  132 
  133         if (npins == 0) {
  134                 device_printf(child, "empty pin mask");
  135                 return (EINVAL);
  136         }
  137 
  138         devi->npins = npins;
  139         devi->pins = malloc(sizeof(uint32_t) * devi->npins, M_DEVBUF, 
  140             M_NOWAIT | M_ZERO);
  141 
  142         if (!devi->pins)
  143                 return (ENOMEM);
  144 
  145         npins = 0;
  146         for (i = 0; i < 32; i++) {
  147 
  148                 if ((mask & (1 << i)) == 0)
  149                         continue;
  150 
  151                 if (i >= sc->sc_npins) {
  152                         device_printf(child, 
  153                             "invalid pin %d, max: %d\n", i, sc->sc_npins - 1);
  154                         return (EINVAL);
  155                 }
  156 
  157                 devi->pins[npins++] = i;
  158                 /*
  159                  * Mark pin as mapped and give warning if it's already mapped
  160                  */
  161                 if (sc->sc_pins_mapped[i]) {
  162                         device_printf(child, 
  163                             "warning: pin %d is already mapped\n", i);
  164                         return (EINVAL);
  165                 }
  166                 sc->sc_pins_mapped[i] = 1;
  167         }
  168 
  169         return (0);
  170 }
  171 
  172 static int
  173 gpiobus_probe(device_t dev)
  174 {
  175         device_set_desc(dev, "GPIO bus");
  176         return (0);
  177 }
  178 
  179 static int
  180 gpiobus_attach(device_t dev)
  181 {
  182         struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev);
  183         int res;
  184 
  185         sc->sc_busdev = dev;
  186         sc->sc_dev = device_get_parent(dev);
  187         res = GPIO_PIN_MAX(sc->sc_dev, &sc->sc_npins);
  188         if (res)
  189                 return (ENXIO);
  190 
  191         /*
  192          * Increase to get number of pins
  193          */
  194         sc->sc_npins++;
  195 
  196         KASSERT(sc->sc_npins != 0, ("GPIO device with no pins"));
  197 
  198         sc->sc_pins_mapped = malloc(sizeof(int) * sc->sc_npins, M_DEVBUF, 
  199             M_NOWAIT | M_ZERO);
  200 
  201         if (!sc->sc_pins_mapped)
  202                 return (ENOMEM);
  203 
  204         /* init bus lock */
  205         GPIOBUS_LOCK_INIT(sc);
  206 
  207         /*
  208          * Get parent's pins and mark them as unmapped
  209          */
  210         bus_enumerate_hinted_children(dev);
  211         return (bus_generic_attach(dev));
  212 }
  213 
  214 /*
  215  * Since this is not a self-enumerating bus, and since we always add
  216  * children in attach, we have to always delete children here.
  217  */
  218 static int
  219 gpiobus_detach(device_t dev)
  220 {
  221         struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev);
  222         int err, ndevs, i;
  223         device_t *devlist;
  224 
  225         KASSERT(mtx_initialized(&sc->sc_mtx),
  226             ("gpiobus mutex not initialized"));
  227         GPIOBUS_LOCK_DESTROY(sc);
  228 
  229         if ((err = bus_generic_detach(dev)) != 0)
  230                 return (err);
  231         if ((err = device_get_children(dev, &devlist, &ndevs)) != 0)
  232                 return (err);
  233         for (i = 0; i < ndevs; i++)
  234                 device_delete_child(dev, devlist[i]);
  235 
  236         if (sc->sc_pins_mapped) {
  237                 free(sc->sc_pins_mapped, M_DEVBUF);
  238                 sc->sc_pins_mapped = NULL;
  239         }
  240         free(devlist, M_TEMP);
  241 
  242         return (0);
  243 }
  244 
  245 static int
  246 gpiobus_suspend(device_t dev)
  247 {
  248 
  249         return (bus_generic_suspend(dev));
  250 }
  251 
  252 static int
  253 gpiobus_resume(device_t dev)
  254 {
  255 
  256         return (bus_generic_resume(dev));
  257 }
  258 
  259 static int
  260 gpiobus_print_child(device_t dev, device_t child)
  261 {
  262         struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
  263         int retval = 0;
  264 
  265         retval += bus_print_child_header(dev, child);
  266         retval += printf(" at pin(s) ");
  267         gpiobus_print_pins(devi);
  268         retval += bus_print_child_footer(dev, child);
  269 
  270         return (retval);
  271 }
  272 
  273 static int
  274 gpiobus_child_location_str(device_t bus, device_t child, char *buf,
  275     size_t buflen)
  276 {
  277         // struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
  278 
  279         snprintf(buf, buflen, "pins=?");
  280         return (0);
  281 }
  282 
  283 static int
  284 gpiobus_child_pnpinfo_str(device_t bus, device_t child, char *buf,
  285     size_t buflen)
  286 {
  287 
  288         *buf = '\0';
  289         return (0);
  290 }
  291 
  292 static device_t
  293 gpiobus_add_child(device_t dev, u_int order, const char *name, int unit)
  294 {
  295         device_t child;
  296         struct gpiobus_ivar *devi;
  297 
  298         child = device_add_child_ordered(dev, order, name, unit);
  299         if (child == NULL) 
  300                 return (child);
  301         devi = malloc(sizeof(struct gpiobus_ivar), M_DEVBUF, M_NOWAIT | M_ZERO);
  302         if (devi == NULL) {
  303                 device_delete_child(dev, child);
  304                 return (0);
  305         }
  306         device_set_ivars(child, devi);
  307         return (child);
  308 }
  309 
  310 static void
  311 gpiobus_hinted_child(device_t bus, const char *dname, int dunit)
  312 {
  313         struct gpiobus_softc *sc = GPIOBUS_SOFTC(bus);
  314         struct gpiobus_ivar *devi;
  315         device_t child;
  316         int pins;
  317 
  318 
  319         child = BUS_ADD_CHILD(bus, 0, dname, dunit);
  320         devi = GPIOBUS_IVAR(child);
  321         resource_int_value(dname, dunit, "pins", &pins);
  322         if (gpiobus_parse_pins(sc, child, pins))
  323                 device_delete_child(bus, child);
  324 }
  325 
  326 static void
  327 gpiobus_lock_bus(device_t busdev)
  328 {
  329         struct gpiobus_softc *sc;
  330 
  331         sc = device_get_softc(busdev);
  332         GPIOBUS_ASSERT_UNLOCKED(sc);
  333         GPIOBUS_LOCK(sc);
  334 }
  335 
  336 static void
  337 gpiobus_unlock_bus(device_t busdev)
  338 {
  339         struct gpiobus_softc *sc;
  340 
  341         sc = device_get_softc(busdev);
  342         GPIOBUS_ASSERT_LOCKED(sc);
  343         GPIOBUS_UNLOCK(sc);
  344 }
  345 
  346 static void
  347 gpiobus_acquire_bus(device_t busdev, device_t child)
  348 {
  349         struct gpiobus_softc *sc;
  350 
  351         sc = device_get_softc(busdev);
  352         GPIOBUS_ASSERT_LOCKED(sc);
  353 
  354         if (sc->sc_owner)
  355                 panic("rb_cpldbus: cannot serialize the access to device.");
  356         sc->sc_owner = child;
  357 }
  358 
  359 static void
  360 gpiobus_release_bus(device_t busdev, device_t child)
  361 {
  362         struct gpiobus_softc *sc;
  363 
  364         sc = device_get_softc(busdev);
  365         GPIOBUS_ASSERT_LOCKED(sc);
  366 
  367         if (!sc->sc_owner)
  368                 panic("rb_cpldbus: releasing unowned bus.");
  369         if (sc->sc_owner != child)
  370                 panic("rb_cpldbus: you don't own the bus. game over.");
  371 
  372         sc->sc_owner = NULL;
  373 }
  374 
  375 static int
  376 gpiobus_pin_setflags(device_t dev, device_t child, uint32_t pin, 
  377     uint32_t flags)
  378 {
  379         struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev);
  380         struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
  381 
  382         if (pin >= devi->npins)
  383                 return (EINVAL);
  384 
  385         return GPIO_PIN_SETFLAGS(sc->sc_dev, devi->pins[pin], flags);
  386 }
  387 
  388 static int
  389 gpiobus_pin_getflags(device_t dev, device_t child, uint32_t pin, 
  390     uint32_t *flags)
  391 {
  392         struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev);
  393         struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
  394 
  395         if (pin >= devi->npins)
  396                 return (EINVAL);
  397 
  398         return GPIO_PIN_GETFLAGS(sc->sc_dev, devi->pins[pin], flags);
  399 }
  400 
  401 static int
  402 gpiobus_pin_getcaps(device_t dev, device_t child, uint32_t pin, 
  403     uint32_t *caps)
  404 {
  405         struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev);
  406         struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
  407 
  408         if (pin >= devi->npins)
  409                 return (EINVAL);
  410 
  411         return GPIO_PIN_GETCAPS(sc->sc_dev, devi->pins[pin], caps);
  412 }
  413 
  414 static int
  415 gpiobus_pin_set(device_t dev, device_t child, uint32_t pin, 
  416     unsigned int value)
  417 {
  418         struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev);
  419         struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
  420 
  421         if (pin >= devi->npins)
  422                 return (EINVAL);
  423 
  424         return GPIO_PIN_SET(sc->sc_dev, devi->pins[pin], value);
  425 }
  426 
  427 static int
  428 gpiobus_pin_get(device_t dev, device_t child, uint32_t pin, 
  429     unsigned int *value)
  430 {
  431         struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev);
  432         struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
  433 
  434         if (pin >= devi->npins)
  435                 return (EINVAL);
  436 
  437         return GPIO_PIN_GET(sc->sc_dev, devi->pins[pin], value);
  438 }
  439 
  440 static int
  441 gpiobus_pin_toggle(device_t dev, device_t child, uint32_t pin)
  442 {
  443         struct gpiobus_softc *sc = GPIOBUS_SOFTC(dev);
  444         struct gpiobus_ivar *devi = GPIOBUS_IVAR(child);
  445 
  446         if (pin >= devi->npins)
  447                 return (EINVAL);
  448 
  449         return GPIO_PIN_TOGGLE(sc->sc_dev, devi->pins[pin]);
  450 }
  451 
  452 static device_method_t gpiobus_methods[] = {
  453         /* Device interface */
  454         DEVMETHOD(device_probe,         gpiobus_probe),
  455         DEVMETHOD(device_attach,        gpiobus_attach),
  456         DEVMETHOD(device_detach,        gpiobus_detach),
  457         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
  458         DEVMETHOD(device_suspend,       gpiobus_suspend),
  459         DEVMETHOD(device_resume,        gpiobus_resume),
  460 
  461         /* Bus interface */
  462         DEVMETHOD(bus_add_child,        gpiobus_add_child),
  463         DEVMETHOD(bus_print_child,      gpiobus_print_child),
  464         DEVMETHOD(bus_driver_added,     bus_generic_driver_added),
  465         DEVMETHOD(bus_child_pnpinfo_str, gpiobus_child_pnpinfo_str),
  466         DEVMETHOD(bus_child_location_str, gpiobus_child_location_str),
  467         DEVMETHOD(bus_hinted_child,     gpiobus_hinted_child),
  468 
  469         /* GPIO protocol */
  470         DEVMETHOD(gpiobus_lock_bus,     gpiobus_lock_bus),
  471         DEVMETHOD(gpiobus_unlock_bus,   gpiobus_unlock_bus),
  472         DEVMETHOD(gpiobus_acquire_bus,  gpiobus_acquire_bus),
  473         DEVMETHOD(gpiobus_release_bus,  gpiobus_release_bus),
  474         DEVMETHOD(gpiobus_pin_getflags, gpiobus_pin_getflags),
  475         DEVMETHOD(gpiobus_pin_getcaps,  gpiobus_pin_getcaps),
  476         DEVMETHOD(gpiobus_pin_setflags, gpiobus_pin_setflags),
  477         DEVMETHOD(gpiobus_pin_get,      gpiobus_pin_get),
  478         DEVMETHOD(gpiobus_pin_set,      gpiobus_pin_set),
  479         DEVMETHOD(gpiobus_pin_toggle,   gpiobus_pin_toggle),
  480 
  481         { 0, 0 }
  482 };
  483 
  484 driver_t gpiobus_driver = {
  485         "gpiobus",
  486         gpiobus_methods,
  487         sizeof(struct gpiobus_softc)
  488 };
  489 
  490 devclass_t      gpiobus_devclass;
  491 
  492 DRIVER_MODULE(gpiobus, gpio, gpiobus_driver, gpiobus_devclass, 0, 0);
  493 MODULE_VERSION(gpiobus, 1);

Cache object: 6eb77debea9c83f42e55753b96818581


[ 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.