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/gpio.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 /* $NetBSD: gpio.c,v 1.17 2008/05/01 22:00:44 cegger Exp $ */
    2 /*      $OpenBSD: gpio.c,v 1.6 2006/01/14 12:33:49 grange Exp $ */
    3 
    4 /*
    5  * Copyright (c) 2004, 2006 Alexander Yurchenko <grange@openbsd.org>
    6  *
    7  * Permission to use, copy, modify, and distribute this software for any
    8  * purpose with or without fee is hereby granted, provided that the above
    9  * copyright notice and this permission notice appear in all copies.
   10  *
   11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   18  */
   19 
   20 #include <sys/cdefs.h>
   21 __KERNEL_RCSID(0, "$NetBSD: gpio.c,v 1.17 2008/05/01 22:00:44 cegger Exp $");
   22 
   23 /*
   24  * General Purpose Input/Output framework.
   25  */
   26 
   27 #include <sys/param.h>
   28 #include <sys/systm.h>
   29 #include <sys/conf.h>
   30 #include <sys/device.h>
   31 #include <sys/ioctl.h>
   32 #include <sys/gpio.h>
   33 #include <sys/vnode.h>
   34 
   35 #include <dev/gpio/gpiovar.h>
   36 
   37 #include "locators.h"
   38 
   39 struct gpio_softc {
   40         device_t sc_dev;
   41 
   42         gpio_chipset_tag_t sc_gc;       /* our GPIO controller */
   43         gpio_pin_t *sc_pins;            /* pins array */
   44         int sc_npins;                   /* total number of pins */
   45 
   46         int sc_opened;
   47         int sc_dying;
   48 };
   49 
   50 int     gpio_match(device_t, cfdata_t, void *);
   51 void    gpio_attach(device_t, device_t, void *);
   52 bool    gpio_resume(device_t PMF_FN_PROTO);
   53 int     gpio_detach(device_t, int);
   54 int     gpio_activate(device_t, enum devact);
   55 int     gpio_search(device_t, cfdata_t, const int *, void *);
   56 int     gpio_print(void *, const char *);
   57 
   58 CFATTACH_DECL_NEW(gpio, sizeof(struct gpio_softc),
   59     gpio_match, gpio_attach, gpio_detach, gpio_activate);
   60 
   61 dev_type_open(gpioopen);
   62 dev_type_close(gpioclose);
   63 dev_type_ioctl(gpioioctl);
   64 
   65 const struct cdevsw gpio_cdevsw = {
   66         gpioopen, gpioclose, noread, nowrite, gpioioctl,
   67         nostop, notty, nopoll, nommap, nokqfilter, D_OTHER,
   68 };
   69 
   70 extern struct cfdriver gpio_cd;
   71 
   72 int
   73 gpio_match(device_t parent, cfdata_t cf, void *aux)
   74 {
   75 
   76         return (1);
   77 }
   78 
   79 bool
   80 gpio_resume(device_t self PMF_FN_ARGS)
   81 {
   82         struct gpio_softc *sc = device_private(self);
   83         int pin;
   84 
   85         for (pin = 0; pin < sc->sc_npins; pin++) {
   86                 gpiobus_pin_ctl(sc->sc_gc, pin, sc->sc_pins[pin].pin_flags);
   87                 gpiobus_pin_write(sc->sc_gc, pin, sc->sc_pins[pin].pin_state);
   88         }
   89         return true;
   90 }
   91 
   92 void
   93 gpio_attach(device_t parent, device_t self, void *aux)
   94 {
   95         struct gpio_softc *sc = device_private(self);
   96         struct gpiobus_attach_args *gba = aux;
   97 
   98         sc->sc_dev = self;
   99         sc->sc_gc = gba->gba_gc;
  100         sc->sc_pins = gba->gba_pins;
  101         sc->sc_npins = gba->gba_npins;
  102 
  103         printf(": %d pins\n", sc->sc_npins);
  104 
  105         if (!pmf_device_register(self, NULL, gpio_resume))
  106                 aprint_error_dev(self, "couldn't establish power handler\n");
  107 
  108         /*
  109          * Attach all devices that can be connected to the GPIO pins
  110          * described in the kernel configuration file.
  111          */
  112         config_search_ia(gpio_search, self, "gpio", sc);
  113 }
  114 
  115 int
  116 gpio_detach(device_t self, int flags)
  117 {
  118 #if 0
  119         int maj, mn;
  120 
  121         /* Locate the major number */
  122         for (maj = 0; maj < nchrdev; maj++)
  123                 if (cdevsw[maj].d_open == gpioopen)
  124                         break;
  125 
  126         /* Nuke the vnodes for any open instances (calls close) */
  127         mn = device_unit(self);
  128         vdevgone(maj, mn, mn, VCHR);
  129 #endif
  130 
  131         return (0);
  132 }
  133 
  134 int
  135 gpio_activate(device_t self, enum devact act)
  136 {
  137         struct gpio_softc *sc = device_private(self);
  138 
  139         switch (act) {
  140         case DVACT_ACTIVATE:
  141                 return (EOPNOTSUPP);
  142         case DVACT_DEACTIVATE:
  143                 sc->sc_dying = 1;
  144                 break;
  145         }
  146 
  147         return (0);
  148 }
  149 
  150 int
  151 gpio_search(device_t parent, cfdata_t cf,
  152     const int *ldesc, void *aux)
  153 {
  154         struct gpio_attach_args ga;
  155 
  156         ga.ga_gpio = aux;
  157         ga.ga_offset = cf->cf_loc[GPIOCF_OFFSET];
  158         ga.ga_mask = cf->cf_loc[GPIOCF_MASK];
  159 
  160         if (config_match(parent, cf, &ga) > 0)
  161                 config_attach(parent, cf, &ga, gpio_print);
  162 
  163         return (0);
  164 }
  165 
  166 int
  167 gpio_print(void *aux, const char *pnp)
  168 {
  169         struct gpio_attach_args *ga = aux;
  170         int i;
  171 
  172         printf(" pins");
  173         for (i = 0; i < 32; i++)
  174                 if (ga->ga_mask & (1 << i))
  175                         printf(" %d", ga->ga_offset + i);
  176 
  177         return (UNCONF);
  178 }
  179 
  180 int
  181 gpiobus_print(void *aux, const char *pnp)
  182 {
  183 #if 0
  184         struct gpiobus_attach_args *gba = aux;
  185 #endif
  186         if (pnp != NULL)
  187                 printf("%s at %s", "gpiobus", pnp);
  188 
  189         return (UNCONF);
  190 }
  191 
  192 int
  193 gpio_pin_map(void *gpio, int offset, u_int32_t mask, struct gpio_pinmap *map)
  194 {
  195         struct gpio_softc *sc = gpio;
  196         int npins, pin, i;
  197 
  198         npins = gpio_npins(mask);
  199         if (npins > sc->sc_npins)
  200                 return (1);
  201 
  202         for (npins = 0, i = 0; i < 32; i++)
  203                 if (mask & (1 << i)) {
  204                         pin = offset + i;
  205                         if (pin < 0 || pin >= sc->sc_npins)
  206                                 return (1);
  207                         if (sc->sc_pins[pin].pin_mapped)
  208                                 return (1);
  209                         sc->sc_pins[pin].pin_mapped = 1;
  210                         map->pm_map[npins++] = pin;
  211                 }
  212         map->pm_size = npins;
  213 
  214         return (0);
  215 }
  216 
  217 void
  218 gpio_pin_unmap(void *gpio, struct gpio_pinmap *map)
  219 {
  220         struct gpio_softc *sc = gpio;
  221         int pin, i;
  222 
  223         for (i = 0; i < map->pm_size; i++) {
  224                 pin = map->pm_map[i];
  225                 sc->sc_pins[pin].pin_mapped = 0;
  226         }
  227 }
  228 
  229 int
  230 gpio_pin_read(void *gpio, struct gpio_pinmap *map, int pin)
  231 {
  232         struct gpio_softc *sc = gpio;
  233 
  234         return (gpiobus_pin_read(sc->sc_gc, map->pm_map[pin]));
  235 }
  236 
  237 void
  238 gpio_pin_write(void *gpio, struct gpio_pinmap *map, int pin, int value)
  239 {
  240         struct gpio_softc *sc = gpio;
  241 
  242         gpiobus_pin_write(sc->sc_gc, map->pm_map[pin], value);
  243         sc->sc_pins[map->pm_map[pin]].pin_state = value;
  244 }
  245 
  246 void
  247 gpio_pin_ctl(void *gpio, struct gpio_pinmap *map, int pin, int flags)
  248 {
  249         struct gpio_softc *sc = gpio;
  250 
  251         return (gpiobus_pin_ctl(sc->sc_gc, map->pm_map[pin], flags));
  252 }
  253 
  254 int
  255 gpio_pin_caps(void *gpio, struct gpio_pinmap *map, int pin)
  256 {
  257         struct gpio_softc *sc = gpio;
  258 
  259         return (sc->sc_pins[map->pm_map[pin]].pin_caps);
  260 }
  261 
  262 int
  263 gpio_npins(u_int32_t mask)
  264 {
  265         int npins, i;
  266 
  267         for (npins = 0, i = 0; i < 32; i++)
  268                 if (mask & (1 << i))
  269                         npins++;
  270 
  271         return (npins);
  272 }
  273 
  274 int
  275 gpioopen(dev_t dev, int flag, int mode,
  276     struct lwp *l)
  277 {
  278         struct gpio_softc *sc;
  279         int ret;
  280 
  281         sc = device_lookup_private(&gpio_cd, minor(dev));
  282         if (sc == NULL)
  283                 return (ENXIO);
  284 
  285         if (sc->sc_opened)
  286                 return (EBUSY);
  287 
  288         if ((ret = gpiobus_open(sc->sc_gc, sc->sc_dev)))
  289                 return ret;
  290 
  291         sc->sc_opened = 1;
  292 
  293         return (0);
  294 }
  295 
  296 int
  297 gpioclose(dev_t dev, int flag, int mode,
  298     struct lwp *l)
  299 {
  300         struct gpio_softc *sc;
  301 
  302         sc = device_lookup_private(&gpio_cd, minor(dev));
  303         gpiobus_close(sc->sc_gc, sc->sc_dev);
  304         sc->sc_opened = 0;
  305 
  306         return (0);
  307 }
  308 
  309 int
  310 gpioioctl(dev_t dev, u_long cmd, void *data, int flag,
  311     struct lwp *l)
  312 {
  313         struct gpio_softc *sc;
  314         gpio_chipset_tag_t gc;
  315         struct gpio_info *info;
  316         struct gpio_pin_op *op;
  317         struct gpio_pin_ctl *ctl;
  318         int pin, value, flags;
  319 
  320         sc = device_lookup_private(&gpio_cd, minor(dev));
  321         gc = sc->sc_gc;
  322 
  323         if (cmd != GPIOINFO && !device_is_active(sc->sc_dev))
  324                 return EBUSY;
  325 
  326         switch (cmd) {
  327         case GPIOINFO:
  328                 info = (struct gpio_info *)data;
  329 
  330                 info->gpio_npins = sc->sc_npins;
  331                 break;
  332         case GPIOPINREAD:
  333                 op = (struct gpio_pin_op *)data;
  334 
  335                 pin = op->gp_pin;
  336                 if (pin < 0 || pin >= sc->sc_npins)
  337                         return (EINVAL);
  338 
  339                 /* return read value */
  340                 op->gp_value = gpiobus_pin_read(gc, pin);
  341                 break;
  342         case GPIOPINWRITE:
  343                 op = (struct gpio_pin_op *)data;
  344 
  345                 pin = op->gp_pin;
  346                 if (pin < 0 || pin >= sc->sc_npins)
  347                         return (EINVAL);
  348                 if (sc->sc_pins[pin].pin_mapped)
  349                         return (EBUSY);
  350 
  351                 value = op->gp_value;
  352                 if (value != GPIO_PIN_LOW && value != GPIO_PIN_HIGH)
  353                         return (EINVAL);
  354 
  355                 gpiobus_pin_write(gc, pin, value);
  356                 /* return old value */
  357                 op->gp_value = sc->sc_pins[pin].pin_state;
  358                 /* update current value */
  359                 sc->sc_pins[pin].pin_state = value;
  360                 break;
  361         case GPIOPINTOGGLE:
  362                 op = (struct gpio_pin_op *)data;
  363 
  364                 pin = op->gp_pin;
  365                 if (pin < 0 || pin >= sc->sc_npins)
  366                         return (EINVAL);
  367                 if (sc->sc_pins[pin].pin_mapped)
  368                         return (EBUSY);
  369 
  370                 value = (sc->sc_pins[pin].pin_state == GPIO_PIN_LOW ?
  371                     GPIO_PIN_HIGH : GPIO_PIN_LOW);
  372                 gpiobus_pin_write(gc, pin, value);
  373                 /* return old value */
  374                 op->gp_value = sc->sc_pins[pin].pin_state;
  375                 /* update current value */
  376                 sc->sc_pins[pin].pin_state = value;
  377                 break;
  378         case GPIOPINCTL:
  379                 ctl = (struct gpio_pin_ctl *)data;
  380 
  381                 pin = ctl->gp_pin;
  382                 if (pin < 0 || pin >= sc->sc_npins)
  383                         return (EINVAL);
  384                 if (sc->sc_pins[pin].pin_mapped)
  385                         return (EBUSY);
  386 
  387                 flags = ctl->gp_flags;
  388                 /* check that the controller supports all requested flags */
  389                 if ((flags & sc->sc_pins[pin].pin_caps) != flags)
  390                         return (ENODEV);
  391 
  392                 ctl->gp_caps = sc->sc_pins[pin].pin_caps;
  393                 /* return old value */
  394                 ctl->gp_flags = sc->sc_pins[pin].pin_flags;
  395                 if (flags > 0) {
  396                         gpiobus_pin_ctl(gc, pin, flags);
  397                         /* update current value */
  398                         sc->sc_pins[pin].pin_flags = flags;
  399                 }
  400                 break;
  401         default:
  402                 return (ENOTTY);
  403         }
  404 
  405         return (0);
  406 }

Cache object: 074f30cdc677c1b0ed648bae17dfec5b


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