Import libgpio.

This is a thin wrapper around the kernel interface which should make
it easier to write GPIO applications.  gpioctl(8) will be converted to
use this library in a separate commit.

Differential Revision:	https://reviews.freebsd.org/D1183
Reviewed by:	adrian, loos
Discussed on:	arm@, embedded@
Relnotes:	yes
This commit is contained in:
rpaulo 2014-11-24 21:49:40 +00:00
parent 57a84aae16
commit 7b5aae7235
7 changed files with 597 additions and 0 deletions

View File

@ -56,6 +56,7 @@ LINE("libftpio", "FTP Connection Management Library (libftpio, \\-lftpio)")
LINE("libform", "Curses Form Library (libform, \\-lform)")
LINE("libgeom", "Userland API Library for Kernel GEOM subsystem (libgeom, \\-lgeom)")
LINE("libgpib", "General-Purpose Instrument Bus (GPIB) library (libgpib, \\-lgpib)")
LINE("libgpio", "General-Purpose Input Output (GPIO) library (libgpio, \\-lgpio)")
LINE("libhammer", "HAMMER Filesystem Userland Library (libhammer, \\-lhammer)")
LINE("libi386", "i386 Architecture Library (libi386, \\-li386)")
LINE("libintl", "Internationalized Message Handling Library (libintl, \\-lintl)")

View File

@ -52,6 +52,7 @@ SUBDIR= ${SUBDIR_ORDERED} \
libfigpar \
libgeom \
${_libgpib} \
libgpio \
${_libgssapi} \
${_librpcsec_gss} \
${_libiconv_modules} \

35
lib/libgpio/Makefile Normal file
View File

@ -0,0 +1,35 @@
# $FreeBSD$
LIB= gpio
SHLIB_MAJOR= 0
SRCS= gpio.c
INCS= libgpio.h
MAN+= gpio.3
CFLAGS+= -I${.CURDIR}
MLINKS= gpio.3 gpio_open.3 \
gpio.3 gpio_open_device.3 \
gpio.3 gpio_close.3 \
gpio.3 gpio_pin_list.3 \
gpio.3 gpio_pin_config.3 \
gpio.3 gpio_pin_set_flags.3 \
gpio.3 gpio_pin_get.3 \
gpio.3 gpio_pin_set.3 \
gpio.3 gpio_pin_low.3 \
gpio.3 gpio_pin_high.3 \
gpio.3 gpio_pin_input.3 \
gpio.3 gpio_pin_output.3 \
gpio.3 gpio_pin_opendrain.3 \
gpio.3 gpio_pin_pushpull.3 \
gpio.3 gpio_pin_tristate.3 \
gpio.3 gpio_pin_pullup.3 \
gpio.3 gpio_pin_pulldown.3 \
gpio.3 gpio_pin_invin.3 \
gpio.3 gpio_pin_invout.3 \
gpio.3 gpio_pin_pulsate.3
WARNS?= 6
.include <bsd.lib.mk>

192
lib/libgpio/gpio.3 Normal file
View File

@ -0,0 +1,192 @@
.\"
.\" Copyright (c) 2014 Rui Paulo
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
.\"
.Dd November 17, 2014
.Dt GPIO 3
.Os
.Sh NAME
.Nm gpio_open ,
.Nm gpio_close
.Nd "library to handle GPIO pins"
.Sh LIBRARY
.Lb libgpio
.Sh SYNOPSIS
.In libgpio.h
.Ft "gpio_handle_t"
.Fn gpio_open "unsigned int unit"
.Ft "gpio_handle_t"
.Fn gpio_open_device "const char *device"
.Ft void
.Fn gpio_close "gpio_handle_t handle"
.Ft int
.Fn gpio_pin_list "gpio_handle_t handle, gpio_config_t **pcfgs"
.Ft int
.Fn gpio_pin_config "gpio_handle_t handle, gpio_config *cfg"
.Ft int
.Fn gpio_pin_set_flags "gpio_handle_t handle, gpio_config_t *cfg"
.Ft gpio_value_t
.Fn gpio_pin_get "gpio_handle_t handle, gpio_pin_t pin"
.Ft int
.Fn gpio_pin_set "gpio_handle_t handle, gpio_pin_t pin, gpio_value_t value"
.Ft int
.Fn gpio_pin_toggle "gpio_handle_t handle, gpio_pin_t pin"
.Ft int
.Fn gpio_pin_low "gpio_handle_t handle, gpio_pin_t pin"
.Ft int
.Fn gpio_pin_high "gpio_handle_t handle, gpio_pin_t pin"
.Ft int
.Fn gpio_pin_input "gpio_handle_t handle, gpio_pin_t pin"
.Ft int
.Fn gpio_pin_output "gpio_handle_t handle, gpio_pin_t pin"
.Ft int
.Fn gpio_pin_opendrain "gpio_handle_t handle, gpio_pin_t pin"
.Ft int
.Fn gpio_pin_pushpull "gpio_handle_t handle, gpio_pin_t pin"
.Ft int
.Fn gpio_pin_tristate "gpio_handle_t handle, gpio_pin_t pin"
.Ft int
.Fn gpio_pin_pullup "gpio_handle_t handle, gpio_pin_t pin"
.Ft int
.Fn gpio_pin_pulldown "gpio_handle_t handle, gpio_pin_t pin"
.Ft int
.Fn gpio_pin_invin "gpio_handle_t handle, gpio_pin_t pin"
.Ft int
.Fn gpio_pin_invout "gpio_handle_t handle, gpio_pin_t pin"
.Ft int
.Fn gpio_pin_pulsate "gpio_handle_t handle, gpio_pin_t pin"
.Sh DESCRIPTION
The
.Nm libgpio
library provides an interface to configure GPIO pins.
The library operates with a
.Ft gpio_handle_t
opaque type which can be created with
.Fn gpio_open
or
.Fn gpio_open_device .
When no more GPIO operations are needed, this handle can be destroyed
with
.Fn gpio_close .
.Pp
To get a list of all available pins, one can call
.Fn gpio_pin_list .
This function takes a pointer to a
.Ft gpio_config_t
which is dynamically allocated.
This pointer should be freed with
.Xr free 3
when it's no longer necessary.
.Pp
The function
.Fn gpio_pin_config
retrieves the current configuration of a pin.
The pin number should be passed in via the
.Ft g_pin
variable which is part of the
.Ft gpio_config_t
structure.
.Pp
The function
.Fn gpio_pin_set_flags
configures a pin with the flags passed in by the
.Ft gpio_config_t
structure.
The pin number should also be passed in through the
.Ft g_pin
variable.
All other structure members will be ignored by this function.
The list of flags can be found in
.Pa /usr/include/sys/gpio.h .
.Pp
The get or set the state of a GPIO pin, the functions
.Fn gpio_pin_get
and
.Fn gpio_pin_set
are available, respectively.
To toggle the state, use
.Fn gpio_pin_toggle .
.Pp
The functions
.Fn gpio_pin_low
and
.Fn gpio_pin_high
are wrappers around
.Fn gpio_pin_set .
.Pp
The functions
.Fn gpio_pin_input ,
.Fn gpio_pin_output ,
.Fn gpio_pin_opendrain ,
.Fn gpio_pin_pushpull ,
.Fn gpio_pin_tristate ,
.Fn gpio_pin_pullup ,
.Fn gpio_pin_pulldown ,
.Fn gpio_pin_invin ,
.Fn gpio_pin_invout
and
.Fn gpio_pin_pulsate
are wrappers around
.Fn gpio_pin_set_flags .
.Sh EXAMPLES
The following example shows how to configure pin 16 as output and then
drive it high:
.Bd -literal
#include <err.h>
#include <libgpio.h>
gpio_handle_t handle;
handle = gpio_open(0);
if (handle == GPIO_HANDLE_INVALID)
err(1, "gpio_open failed");
gpio_pin_output(handle, 16);
gpio_pin_high(handle, 16);
gpio_close(handle);
.Ed
.Pp
The following example shows how to get a configuration of a pin:
.Bd -literal
gpio_config_t cfg;
cfg.g_pin = 32;
gpio_pin_config(handle, &cfg);
.Ed
.Pp
The structure will contain the name of the pin and its flags.
.Sh SEE ALSO
.Xr gpiobus 4 ,
.Xr gpioctl 8
.Sh HISTORY
The
.Nm libgpio
library first appeared in
.Fx 11.0 .
.Sh AUTHORS
The
.Nm libgpio
library was implemented by
.An Rui Paulo Aq Mt rpaulo@FreeBSD.org .

262
lib/libgpio/gpio.c Normal file
View File

@ -0,0 +1,262 @@
/*-
* Copyright (c) 2013-2014 Rui Paulo <rpaulo@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <libgpio.h>
gpio_handle_t
gpio_open(unsigned int unit)
{
char device[16];
snprintf(device, sizeof(device), "/dev/gpioc%u", unit);
return (gpio_open_device(device));
}
gpio_handle_t
gpio_open_device(const char *device)
{
int fd, maxpins;
int serr;
fd = open(device, O_RDONLY);
if (fd < 0)
return (GPIO_INVALID_HANDLE);
/*
* Check whether a simple ioctl works.
*/
if (ioctl(fd, GPIOMAXPIN, &maxpins) < 0) {
serr = errno;
close(fd);
errno = serr;
return (GPIO_INVALID_HANDLE);
}
return (fd);
}
void
gpio_close(gpio_handle_t handle)
{
close(handle);
}
int
gpio_pin_list(gpio_handle_t handle, gpio_config_t **pcfgs)
{
int maxpins, i;
gpio_config_t *cfgs;
*pcfgs = NULL;
if (ioctl(handle, GPIOMAXPIN, &maxpins) < 0)
return (-1);
/* Reasonable values. */
if (maxpins < 0 || maxpins > 4096) {
errno = EINVAL;
return (-1);
}
cfgs = calloc(maxpins, sizeof(*cfgs));
if (cfgs == NULL)
return (-1);
for (i = 0; i <= maxpins; i++) {
cfgs[i].g_pin = i;
gpio_pin_config(handle, &cfgs[i]);
}
*pcfgs = cfgs;
return (maxpins);
}
int
gpio_pin_config(gpio_handle_t handle, gpio_config_t *cfg)
{
struct gpio_pin gppin;
if (cfg == NULL)
return (-1);
gppin.gp_pin = cfg->g_pin;
if (ioctl(handle, GPIOGETCONFIG, &gppin) < 0)
return (-1);
strlcpy(cfg->g_name, gppin.gp_name, GPIOMAXNAME);
cfg->g_caps = gppin.gp_caps;
cfg->g_flags = gppin.gp_flags;
return (0);
}
int
gpio_pin_set_flags(gpio_handle_t handle, gpio_config_t *cfg)
{
struct gpio_pin gppin;
if (cfg == NULL)
return (-1);
gppin.gp_pin = cfg->g_pin;
gppin.gp_flags = cfg->g_flags;
if (ioctl(handle, GPIOSETCONFIG, &gppin) < 0)
return (-1);
return (0);
}
gpio_value_t
gpio_pin_get(gpio_handle_t handle, gpio_pin_t pin)
{
struct gpio_req gpreq;
bzero(&gpreq, sizeof(gpreq));
gpreq.gp_pin = pin;
if (ioctl(handle, GPIOGET, &gpreq) < 0)
return (GPIO_VALUE_INVALID);
return (gpreq.gp_value);
}
int
gpio_pin_set(gpio_handle_t handle, gpio_pin_t pin, gpio_value_t value)
{
struct gpio_req gpreq;
if (value == GPIO_VALUE_INVALID)
return (-1);
bzero(&gpreq, sizeof(gpreq));
gpreq.gp_pin = pin;
gpreq.gp_value = value;
if (ioctl(handle, GPIOSET, &gpreq) < 0)
return (-1);
return (0);
}
int
gpio_pin_toggle(gpio_handle_t handle, gpio_pin_t pin)
{
gpio_value_t value;
value = gpio_pin_get(handle, pin);
if (value == GPIO_VALUE_INVALID)
return (-1);
value = !value;
return (gpio_pin_set(handle, pin, value));
}
int
gpio_pin_low(gpio_handle_t handle, gpio_pin_t pin)
{
return (gpio_pin_set(handle, pin, GPIO_VALUE_LOW));
}
int
gpio_pin_high(gpio_handle_t handle, gpio_pin_t pin)
{
return (gpio_pin_set(handle, pin, GPIO_VALUE_HIGH));
}
static int
gpio_pin_set_flag(gpio_handle_t handle, gpio_pin_t pin, uint32_t flag)
{
gpio_config_t cfg;
bzero(&cfg, sizeof(cfg));
cfg.g_pin = pin;
if (gpio_pin_config(handle, &cfg) < 0)
return (-1);
cfg.g_flags = flag;
return (gpio_pin_set_flags(handle, &cfg));
}
int
gpio_pin_input(gpio_handle_t handle, gpio_pin_t pin)
{
return (gpio_pin_set_flag(handle, pin, GPIO_PIN_INPUT));
}
int
gpio_pin_output(gpio_handle_t handle, gpio_pin_t pin)
{
return (gpio_pin_set_flag(handle, pin, GPIO_PIN_OUTPUT));
}
int
gpio_pin_opendrain(gpio_handle_t handle, gpio_pin_t pin)
{
return (gpio_pin_set_flag(handle, pin, GPIO_PIN_OPENDRAIN));
}
int
gpio_pin_pushpull(gpio_handle_t handle, gpio_pin_t pin)
{
return (gpio_pin_set_flag(handle, pin, GPIO_PIN_PUSHPULL));
}
int
gpio_pin_tristate(gpio_handle_t handle, gpio_pin_t pin)
{
return (gpio_pin_set_flag(handle, pin, GPIO_PIN_TRISTATE));
}
int
gpio_pin_pullup(gpio_handle_t handle, gpio_pin_t pin)
{
return (gpio_pin_set_flag(handle, pin, GPIO_PIN_PULLUP));
}
int
gpio_pin_pulldown(gpio_handle_t handle, gpio_pin_t pin)
{
return (gpio_pin_set_flag(handle, pin, GPIO_PIN_PULLDOWN));
}
int
gpio_pin_invin(gpio_handle_t handle, gpio_pin_t pin)
{
return (gpio_pin_set_flag(handle, pin, GPIO_PIN_INVIN));
}
int
gpio_pin_invout(gpio_handle_t handle, gpio_pin_t pin)
{
return (gpio_pin_set_flag(handle, pin, GPIO_PIN_INVOUT));
}
int
gpio_pin_pulsate(gpio_handle_t handle, gpio_pin_t pin)
{
return (gpio_pin_set_flag(handle, pin, GPIO_PIN_PULSATE));
}

105
lib/libgpio/libgpio.h Normal file
View File

@ -0,0 +1,105 @@
/*-
* Copyright (c) 2013-2014 Rui Paulo <rpaulo@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _LIBGPIO_H_
#define _LIBGPIO_H_
#include <sys/gpio.h>
__BEGIN_DECLS
#define GPIO_INVALID_HANDLE -1
typedef int gpio_handle_t;
typedef uint32_t gpio_pin_t;
/*
* Structure describing a GPIO pin configuration.
*/
typedef struct {
gpio_pin_t g_pin;
char g_name[GPIOMAXNAME];
uint32_t g_caps;
uint32_t g_flags;
} gpio_config_t;
typedef enum {
GPIO_VALUE_INVALID = -1,
GPIO_VALUE_LOW = GPIO_PIN_LOW,
GPIO_VALUE_HIGH = GPIO_PIN_HIGH
} gpio_value_t;
/*
* Open /dev/gpiocN or a specific device.
*/
gpio_handle_t gpio_open(unsigned int);
gpio_handle_t gpio_open_device(const char *);
void gpio_close(gpio_handle_t);
/*
* Get a list of all the GPIO pins.
*/
int gpio_pin_list(gpio_handle_t, gpio_config_t **);
/*
* GPIO pin configuration.
*
* Retrieve the configuration of a specific GPIO pin. The pin number is
* passed through the gpio_config_t structure.
*/
int gpio_pin_config(gpio_handle_t, gpio_config_t *);
/*
* Sets the GPIO flags on a specific GPIO pin. The pin number and the flags
* to be set are passed through the gpio_config_t structure.
*/
int gpio_pin_set_flags(gpio_handle_t, gpio_config_t *);
/*
* GPIO pin values.
*/
int gpio_pin_get(gpio_handle_t, gpio_pin_t);
int gpio_pin_set(gpio_handle_t, gpio_pin_t, int);
int gpio_pin_toggle(gpio_handle_t, gpio_pin_t);
/*
* Helper functions to set pin states.
*/
int gpio_pin_low(gpio_handle_t, gpio_pin_t);
int gpio_pin_high(gpio_handle_t, gpio_pin_t);
/*
* Helper functions to configure pins.
*/
int gpio_pin_input(gpio_handle_t, gpio_pin_t);
int gpio_pin_output(gpio_handle_t, gpio_pin_t);
int gpio_pin_opendrain(gpio_handle_t, gpio_pin_t);
int gpio_pin_pushpull(gpio_handle_t, gpio_pin_t);
int gpio_pin_tristate(gpio_handle_t, gpio_pin_t);
int gpio_pin_pullup(gpio_handle_t, gpio_pin_t);
int gpio_pin_pulldown(gpio_handle_t, gpio_pin_t);
int gpio_pin_invin(gpio_handle_t, gpio_pin_t);
int gpio_pin_invout(gpio_handle_t, gpio_pin_t);
int gpio_pin_pulsate(gpio_handle_t, gpio_pin_t);
__END_DECLS
#endif /* _LIBGPIO_H_ */

View File

@ -54,6 +54,7 @@ LIBFIGPAR?= ${DESTDIR}${LIBDIR}/libfigpar.a
LIBFL?= "don't use LIBFL, use LIBL"
LIBFORM?= ${DESTDIR}${LIBDIR}/libform.a
LIBG2C?= ${DESTDIR}${LIBDIR}/libg2c.a
LIBGPIO?= ${DESTDIR}${LIBDIR}/libgpio.a
LIBGEOM?= ${DESTDIR}${LIBDIR}/libgeom.a
LIBGNUREGEX?= ${DESTDIR}${LIBDIR}/libgnuregex.a
LIBGSSAPI?= ${DESTDIR}${LIBDIR}/libgssapi.a