root/dev/gpio/gpio.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. gpio_match
  2. gpio_attach
  3. gpio_detach
  4. gpio_search
  5. gpio_print
  6. gpiobus_print
  7. gpio_pin_map
  8. gpio_pin_unmap
  9. gpio_pin_read
  10. gpio_pin_write
  11. gpio_pin_ctl
  12. gpio_pin_caps
  13. gpio_npins
  14. gpioopen
  15. gpioclose
  16. gpioioctl

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

/* [<][>][^][v][top][bottom][index][help] */