Reworked gpioctl(8) command to reflect recent gpio(4) changes.
This commit is contained in:
parent
8964d40bc5
commit
32eeaba5d3
|
@ -1,7 +1,7 @@
|
|||
# $NetBSD: Makefile,v 1.3 2009/04/22 15:23:03 lukem Exp $
|
||||
# $NetBSD: Makefile,v 1.4 2009/07/25 16:18:09 mbalmer Exp $
|
||||
|
||||
PROG= gpioctl
|
||||
SRCS= gpioctl.c
|
||||
SRCS= gpioctl.c strtonum.c
|
||||
|
||||
MAN= gpioctl.8
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.\" $NetBSD: gpioctl.8,v 1.4 2008/01/09 15:56:27 xtraeme Exp $
|
||||
.\" $OpenBSD: gpioctl.8,v 1.5 2004/12/02 05:11:40 grange Exp $
|
||||
.\" $NetBSD: gpioctl.8,v 1.5 2009/07/25 16:18:09 mbalmer Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2009 Marc Balmer <marc@msys.ch>
|
||||
.\" Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org>
|
||||
.\"
|
||||
.\" Permission to use, copy, modify, and distribute this software for any
|
||||
|
@ -15,66 +15,71 @@
|
|||
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.Dd January 9, 2008
|
||||
.Dd July 15, 2009
|
||||
.Dt GPIOCTL 8
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm gpioctl
|
||||
.Nd control GPIO devices
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl hq
|
||||
.Op Fl d Ar device
|
||||
.Op Ar pin
|
||||
.Op Ar 0 | 1 | 2
|
||||
.Nm
|
||||
.Op Fl hq
|
||||
.Op Fl d Ar device
|
||||
.Fl c
|
||||
.Nm gpioctl
|
||||
.Op Fl q
|
||||
.Ar device
|
||||
attach
|
||||
.Ar device
|
||||
.Ar offset
|
||||
.Ar mask
|
||||
.Nm gpioctl
|
||||
.Op Fl q
|
||||
.Ar device
|
||||
detach
|
||||
.Ar device
|
||||
.Nm gpioctl
|
||||
.Op Fl q
|
||||
.Ar device
|
||||
.Ar pin
|
||||
.Op Ar 0 | 1 | 2
|
||||
.Nm gpioctl
|
||||
.Op Fl q
|
||||
.Ar device
|
||||
.Ar pin
|
||||
.Op Ar on | off | toggle
|
||||
.Nm gpioctl
|
||||
.Op Fl q
|
||||
.Ar device
|
||||
.Ar pin
|
||||
set
|
||||
.Op Ar flags
|
||||
.Op Ar name
|
||||
.Nm gpioctl
|
||||
.Op Fl q
|
||||
.Ar device
|
||||
.Ar pin
|
||||
unset
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
program allows manipulation of
|
||||
.Tn GPIO
|
||||
program allows manipulation of GPIO
|
||||
(General Purpose Input/Output) device pins.
|
||||
Such devices can be either part of the chipset or embedded
|
||||
.Tn CPU ,
|
||||
Such devices can be either part of the chipset or embedded CPU,
|
||||
or a separate chip.
|
||||
The usual way of using
|
||||
.Tn GPIO
|
||||
is to connect some simple devices such as LEDs, 1-wire thermal sensors,
|
||||
etc., to its pins.
|
||||
The usual way of using GPIO
|
||||
is to connect some simple devices such as LEDs and 1-wire thermal sensors
|
||||
to its pins.
|
||||
.Pp
|
||||
Each
|
||||
.Tn GPIO
|
||||
device has an associated device file in the
|
||||
Each GPIO device has an associated device file in the
|
||||
.Pa /dev
|
||||
directory.
|
||||
By default
|
||||
.Nm
|
||||
uses
|
||||
.Pa /dev/gpio0 ,
|
||||
which corresponds to the first found
|
||||
.Tn GPIO
|
||||
device in the system.
|
||||
If more than one
|
||||
.Tn GPIO
|
||||
device is present, an alternative device file can be specified with the
|
||||
.Fl d
|
||||
option in order to access a particular
|
||||
.Tn GPIO
|
||||
device.
|
||||
.Ar device
|
||||
can be specified with or without the
|
||||
.Pa /dev
|
||||
prefix.
|
||||
For example,
|
||||
.Pa /dev/gpio0
|
||||
or
|
||||
.Pa gpio0 .
|
||||
.Pp
|
||||
When executed without any arguments,
|
||||
.Nm
|
||||
reads information about the
|
||||
.Tn GPIO
|
||||
device and displays it.
|
||||
.Pp
|
||||
.Tn GPIO
|
||||
pins can be either
|
||||
GPIO pins can be either
|
||||
.Dq read
|
||||
or
|
||||
.Dq written
|
||||
|
@ -82,9 +87,7 @@ with the values of logical 0 or 1.
|
|||
If only a
|
||||
.Ar pin
|
||||
number is specified on the command line, the pin state will be read
|
||||
from the
|
||||
.Tn GPIO
|
||||
controller and displayed.
|
||||
from the GPIO controller and displayed.
|
||||
To write to a pin, a value must be specified after the
|
||||
.Ar pin
|
||||
number.
|
||||
|
@ -92,15 +95,28 @@ Values can be either 0 or 1.
|
|||
A value of 2 has a special meaning: it
|
||||
.Dq toggles
|
||||
the pin, i.e. changes its state to the opposite.
|
||||
Instead of the numerical values, the word
|
||||
.Ar on ,
|
||||
.Ar off ,
|
||||
or
|
||||
.Ar toggle
|
||||
can be used.
|
||||
.Pp
|
||||
Each pin can be configured with different flags with the
|
||||
.Fl c
|
||||
option.
|
||||
The following configuration flags are supported by the
|
||||
.Tn GPIO
|
||||
framework:
|
||||
Only pins that have been configured at securelevel 0, typically during system
|
||||
startup, are accessible once the securelevel has been raised.
|
||||
Pins can be given symbolic names for easier use.
|
||||
Besides using individual pins, device drivers that use GPIO pins can be
|
||||
attached to a
|
||||
.Xr gpio 4
|
||||
device using the
|
||||
.Nm
|
||||
command.
|
||||
.Pp
|
||||
.Bl -tag -width XXXXXXX -offset indent -compact
|
||||
The following configuration
|
||||
.Ar flags
|
||||
are supported by the GPIO framework:
|
||||
.Pp
|
||||
.Bl -tag -width Ds -offset indent -compact
|
||||
.It in
|
||||
input direction
|
||||
.It out
|
||||
|
@ -123,31 +139,23 @@ invert input
|
|||
invert output
|
||||
.El
|
||||
.Pp
|
||||
Note that not all the flags can be supported by the particular
|
||||
.Tn GPIO
|
||||
controller.
|
||||
The list of supported flags is always displayed when executing
|
||||
.Nm
|
||||
with the
|
||||
.Fl c
|
||||
option.
|
||||
If only a
|
||||
.Ar pin
|
||||
number is specified on the command line, the current pin flags will be
|
||||
displayed.
|
||||
To change pin flags, a new flags set separated by spaces must be
|
||||
specified after the
|
||||
.Ar pin
|
||||
number.
|
||||
Note that not all the flags may be supported by the particular GPIO controller.
|
||||
.Pp
|
||||
The
|
||||
.Fl q
|
||||
option causes
|
||||
When executed with only the
|
||||
.Xr gpio 4
|
||||
device name as argument,
|
||||
.Nm
|
||||
to operate quietly i.e. nothing is printed to stdout.
|
||||
The
|
||||
.Fl h
|
||||
option displays a usage summary.
|
||||
reads information about the
|
||||
.Tn GPIO
|
||||
device and displays it.
|
||||
At securelevel 0 the number of physically available pins is displayed,
|
||||
at higher securelevels the number of configured (set) pins is displayed.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl q
|
||||
Operate quietly i.e. nothing is printed to stdout.
|
||||
.El
|
||||
.Sh FILES
|
||||
.Bl -tag -width "/dev/gpiou" -compact
|
||||
.It /dev/gpio Ns Ar u
|
||||
|
@ -158,17 +166,33 @@ file.
|
|||
.Sh EXAMPLES
|
||||
Configure pin 20 to have push-pull output:
|
||||
.Pp
|
||||
.Dl # gpioctl -c 20 out pp
|
||||
.Dl # gpioctl gpio0 20 set out pp
|
||||
.Pp
|
||||
Write logical 1 to pin 20:
|
||||
.Pp
|
||||
.Dl # gpioctl 20 1
|
||||
.Dl # gpioctl gpio0 20 1
|
||||
.Pp
|
||||
Attach a
|
||||
.Xr onewire 4
|
||||
bus on a
|
||||
.Xr gpioow 4
|
||||
device on pin 4:
|
||||
.Pp
|
||||
.Dl # gpioctl gpio0 attach gpioow 4 0x01
|
||||
.Pp
|
||||
Detach the gpioow0 device:
|
||||
.Pp
|
||||
.Dl # gpioctl gpio0 detach gpioow0
|
||||
.Pp
|
||||
Configure pin 5 as output and name it error_led:
|
||||
.Pp
|
||||
.Dl # gpioctl gpio0 5 set out error_led
|
||||
.Pp
|
||||
Toggle the error_led:
|
||||
.Pp
|
||||
.Dl # gpioctl gpio0 error_led 2
|
||||
.Sh SEE ALSO
|
||||
.Xr elansc 4 ,
|
||||
.Xr gcscpcib 4 ,
|
||||
.Xr gpio 4 ,
|
||||
.Xr gscpcib 4 ,
|
||||
.Xr nsclpcsio 4
|
||||
.Xr gpio 4
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
|
@ -181,3 +205,5 @@ The
|
|||
.Nm
|
||||
program was written by
|
||||
.An Alexander Yurchenko Aq grange@openbsd.org .
|
||||
Device attachment was added by
|
||||
.An Marc Balmer Aq marc@msys.ch .
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* $NetBSD: gpioctl.c,v 1.5 2008/01/09 16:08:33 xtraeme Exp $ */
|
||||
/* $OpenBSD: gpioctl.c,v 1.2 2004/08/08 00:05:09 deraadt Exp $ */
|
||||
/* $NetBSD: gpioctl.c,v 1.6 2009/07/25 16:18:09 mbalmer Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Marc Balmer <mbalmer@openbsd.org>
|
||||
* Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
|
@ -25,25 +26,34 @@
|
|||
#include <sys/ioctl.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <paths.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define _PATH_DEV_GPIO "/dev/gpio0"
|
||||
|
||||
static const char *device = _PATH_DEV_GPIO;
|
||||
static int devfd = -1;
|
||||
static int quiet = 0;
|
||||
char *dev;
|
||||
int devfd = -1;
|
||||
int quiet = 0;
|
||||
|
||||
static void getinfo(void);
|
||||
static void pinread(int);
|
||||
static void pinwrite(int, int);
|
||||
static void pinctl(int, char *[], int);
|
||||
static void usage(void);
|
||||
void getinfo(void);
|
||||
void gpioread(int, char *);
|
||||
void gpiowrite(int, char *, int);
|
||||
void gpioset(int pin, char *name, int flags, char *alias);
|
||||
void gpiounset(int pin, char *name);
|
||||
void devattach(char *, int, u_int32_t);
|
||||
void devdetach(char *);
|
||||
|
||||
static const struct bitstr {
|
||||
__dead void usage(void);
|
||||
|
||||
extern long long strtonum(const char *numstr, long long minval,
|
||||
long long maxval, const char **errstrp);
|
||||
|
||||
const struct bitstr {
|
||||
unsigned int mask;
|
||||
const char *string;
|
||||
} pinflags[] = {
|
||||
|
@ -56,33 +66,28 @@ static const struct bitstr {
|
|||
{ GPIO_PIN_PULLUP, "pu" },
|
||||
{ GPIO_PIN_PULLDOWN, "pd" },
|
||||
{ GPIO_PIN_INVIN, "iin" },
|
||||
{ GPIO_PIN_INVOUT, "iiout" },
|
||||
{ GPIO_PIN_INVOUT, "iout" },
|
||||
{ 0, NULL },
|
||||
};
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int ch;
|
||||
const struct bitstr *bs;
|
||||
int pin, ch, n, fl = 0, value = 0;
|
||||
const char *errstr;
|
||||
char *ep;
|
||||
int do_ctl = 0;
|
||||
int pin = 0, value = 0;
|
||||
int ga_offset = -1;
|
||||
u_int32_t ga_mask = 0;
|
||||
long lval;
|
||||
char *nam = NULL;
|
||||
char devn[32];
|
||||
|
||||
setprogname(argv[0]);
|
||||
|
||||
while ((ch = getopt(argc, argv, "cd:hq")) != -1)
|
||||
while ((ch = getopt(argc, argv, "q")) != -1)
|
||||
switch (ch) {
|
||||
case 'c':
|
||||
do_ctl = 1;
|
||||
break;
|
||||
case 'd':
|
||||
device = optarg;
|
||||
break;
|
||||
case 'q':
|
||||
quiet = 1;
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
/* NOTREACHED */
|
||||
|
@ -90,129 +95,199 @@ main(int argc, char *argv[])
|
|||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc > 0) {
|
||||
pin = strtol(argv[0], &ep, 10);
|
||||
if (*argv[0] == '\0' || *ep != '\0' || pin < 0)
|
||||
errx(EXIT_FAILURE, "%s: invalid pin", argv[0]);
|
||||
if (argc < 1)
|
||||
usage();
|
||||
dev = argv[0];
|
||||
|
||||
if (strncmp(_PATH_DEV, dev, sizeof(_PATH_DEV) - 1)) {
|
||||
(void)snprintf(devn, sizeof(devn), "%s%s", _PATH_DEV, dev);
|
||||
dev = devn;
|
||||
}
|
||||
|
||||
if ((devfd = open(device, O_RDWR)) == -1)
|
||||
err(EXIT_FAILURE, "%s", device);
|
||||
if ((devfd = open(dev, O_RDWR)) == -1)
|
||||
err(EXIT_FAILURE, "%s", dev);
|
||||
|
||||
if (argc == 0 && !do_ctl) {
|
||||
if (argc == 1) {
|
||||
getinfo();
|
||||
} else if (argc == 1) {
|
||||
if (do_ctl)
|
||||
pinctl(pin, NULL, 0);
|
||||
else
|
||||
pinread(pin);
|
||||
} else if (argc > 1) {
|
||||
if (do_ctl) {
|
||||
pinctl(pin, argv + 1, argc - 1);
|
||||
} else {
|
||||
value = strtol(argv[1], &ep, 10);
|
||||
if (*argv[1] == '\0' || *ep != '\0')
|
||||
errx(EXIT_FAILURE, "%s: invalid value",
|
||||
argv[1]);
|
||||
pinwrite(pin, value);
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[1], "attach")) {
|
||||
char *driver, *offset, *mask;
|
||||
|
||||
if (argc != 5)
|
||||
usage();
|
||||
|
||||
driver = argv[2];
|
||||
offset = argv[3];
|
||||
mask = argv[4];
|
||||
|
||||
ga_offset = strtonum(offset, 0, INT_MAX, &errstr);
|
||||
if (errstr)
|
||||
errx(EXIT_FAILURE, "offset is %s: %s", errstr, offset);
|
||||
lval = strtol(mask, &ep, 0);
|
||||
if (*mask == '\0' || *ep != '\0')
|
||||
errx(EXIT_FAILURE, "invalid mask (not a number)");
|
||||
if ((errno == ERANGE && (lval == LONG_MAX
|
||||
|| lval == LONG_MIN)) || (unsigned long)lval > UINT_MAX)
|
||||
errx(EXIT_FAILURE, "mask out of range");
|
||||
ga_mask = lval;
|
||||
devattach(driver, ga_offset, ga_mask);
|
||||
return EXIT_SUCCESS;
|
||||
} else if (!strcmp(argv[1], "detach")) {
|
||||
if (argc != 3)
|
||||
usage();
|
||||
devdetach(argv[2]);
|
||||
} else {
|
||||
usage();
|
||||
/* NOTREACHED */
|
||||
char *nm = NULL;
|
||||
|
||||
/* expecting a pin number or name */
|
||||
pin = strtonum(argv[1], 0, INT_MAX, &errstr);
|
||||
if (errstr)
|
||||
nm = argv[1]; /* try named pin */
|
||||
if (argc > 2) {
|
||||
if (!strcmp(argv[2], "set")) {
|
||||
for (n = 3; n < argc; n++) {
|
||||
for (bs = pinflags; bs->string != NULL;
|
||||
bs++) {
|
||||
if (!strcmp(argv[n],
|
||||
bs->string)) {
|
||||
fl |= bs->mask;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (bs->string == NULL)
|
||||
nam = argv[n];
|
||||
}
|
||||
gpioset(pin, nm, fl, nam);
|
||||
} else if (!strcmp(argv[2], "unset")) {
|
||||
gpiounset(pin, nm);
|
||||
} else {
|
||||
value = strtonum(argv[2], INT_MIN, INT_MAX,
|
||||
&errstr);
|
||||
if (errstr) {
|
||||
if (!strcmp(argv[2], "on"))
|
||||
value = 1;
|
||||
else if (!strcmp(argv[2], "off"))
|
||||
value = 0;
|
||||
else if (!strcmp(argv[2], "toggle"))
|
||||
value = 2;
|
||||
else
|
||||
errx(EXIT_FAILURE,
|
||||
"%s: invalid value",
|
||||
argv[2]);
|
||||
}
|
||||
gpiowrite(pin, nm, value);
|
||||
}
|
||||
} else
|
||||
gpioread(pin, nm);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
getinfo(void)
|
||||
{
|
||||
struct gpio_info info;
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
if (ioctl(devfd, GPIOINFO, &info) == -1)
|
||||
err(EXIT_FAILURE, "GPIOINFO");
|
||||
|
||||
if (quiet)
|
||||
return;
|
||||
|
||||
printf("%s: %d pins\n", device, info.gpio_npins);
|
||||
printf("%s: %d pins\n", dev, info.gpio_npins);
|
||||
}
|
||||
|
||||
static void
|
||||
pinread(int pin)
|
||||
void
|
||||
gpioread(int pin, char *gp_name)
|
||||
{
|
||||
struct gpio_pin_op op;
|
||||
struct gpio_req req;
|
||||
|
||||
memset(&op, 0, sizeof(op));
|
||||
op.gp_pin = pin;
|
||||
if (ioctl(devfd, GPIOPINREAD, &op) == -1)
|
||||
err(EXIT_FAILURE, "GPIOPINREAD");
|
||||
memset(&req, 0, sizeof(req));
|
||||
if (gp_name != NULL)
|
||||
strlcpy(req.gp_name, gp_name, sizeof(req.gp_name));
|
||||
else
|
||||
req.gp_pin = pin;
|
||||
|
||||
if (ioctl(devfd, GPIOREAD, &req) == -1)
|
||||
err(EXIT_FAILURE, "GPIOREAD");
|
||||
|
||||
if (quiet)
|
||||
return;
|
||||
|
||||
printf("pin %d: state %d\n", pin, op.gp_value);
|
||||
if (gp_name)
|
||||
printf("pin %s: state %d\n", gp_name, req.gp_value);
|
||||
else
|
||||
printf("pin %d: state %d\n", pin, req.gp_value);
|
||||
}
|
||||
|
||||
static void
|
||||
pinwrite(int pin, int value)
|
||||
void
|
||||
gpiowrite(int pin, char *gp_name, int value)
|
||||
{
|
||||
struct gpio_pin_op op;
|
||||
struct gpio_req req;
|
||||
|
||||
if (value < 0 || value > 2)
|
||||
errx(EXIT_FAILURE, "%d: invalid value", value);
|
||||
|
||||
memset(&op, 0, sizeof(op));
|
||||
op.gp_pin = pin;
|
||||
op.gp_value = (value == 0 ? GPIO_PIN_LOW : GPIO_PIN_HIGH);
|
||||
memset(&req, 0, sizeof(req));
|
||||
if (gp_name != NULL)
|
||||
strlcpy(req.gp_name, gp_name, sizeof(req.gp_name));
|
||||
else
|
||||
req.gp_pin = pin;
|
||||
req.gp_value = (value == 0 ? GPIO_PIN_LOW : GPIO_PIN_HIGH);
|
||||
if (value < 2) {
|
||||
if (ioctl(devfd, GPIOPINWRITE, &op) == -1)
|
||||
err(EXIT_FAILURE, "GPIOPINWRITE");
|
||||
if (ioctl(devfd, GPIOWRITE, &req) == -1)
|
||||
err(EXIT_FAILURE, "GPIOWRITE");
|
||||
} else {
|
||||
if (ioctl(devfd, GPIOPINTOGGLE, &op) == -1)
|
||||
err(EXIT_FAILURE, "GPIOPINTOGGLE");
|
||||
if (ioctl(devfd, GPIOTOGGLE, &req) == -1)
|
||||
err(EXIT_FAILURE, "GPIOTOGGLE");
|
||||
}
|
||||
|
||||
if (quiet)
|
||||
return;
|
||||
|
||||
printf("pin %d: state %d -> %d\n", pin, op.gp_value,
|
||||
(value < 2 ? value : 1 - op.gp_value));
|
||||
if (gp_name)
|
||||
printf("pin %s: state %d -> %d\n", gp_name, req.gp_value,
|
||||
(value < 2 ? value : 1 - req.gp_value));
|
||||
else
|
||||
printf("pin %d: state %d -> %d\n", pin, req.gp_value,
|
||||
(value < 2 ? value : 1 - req.gp_value));
|
||||
}
|
||||
|
||||
static void
|
||||
pinctl(int pin, char *flags[], int nflags)
|
||||
void
|
||||
gpioset(int pin, char *name, int fl, char *alias)
|
||||
{
|
||||
struct gpio_pin_ctl ctl;
|
||||
int fl = 0;
|
||||
struct gpio_set set;
|
||||
const struct bitstr *bs;
|
||||
int i;
|
||||
|
||||
memset(&ctl, 0, sizeof(ctl));
|
||||
ctl.gp_pin = pin;
|
||||
if (flags != NULL) {
|
||||
for (i = 0; i < nflags; i++)
|
||||
for (bs = pinflags; bs->string != NULL; bs++)
|
||||
if (strcmp(flags[i], bs->string) == 0) {
|
||||
fl |= bs->mask;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ctl.gp_flags = fl;
|
||||
if (ioctl(devfd, GPIOPINCTL, &ctl) == -1)
|
||||
err(EXIT_FAILURE, "GPIOPINCTL");
|
||||
memset(&set, 0, sizeof(set));
|
||||
if (name != NULL)
|
||||
strlcpy(set.gp_name, name, sizeof(set.gp_name));
|
||||
else
|
||||
set.gp_pin = pin;
|
||||
set.gp_flags = fl;
|
||||
|
||||
if (alias != NULL)
|
||||
strlcpy(set.gp_name2, alias, sizeof(set.gp_name2));
|
||||
|
||||
if (ioctl(devfd, GPIOSET, &set) == -1)
|
||||
err(EXIT_FAILURE, "GPIOSET");
|
||||
|
||||
if (quiet)
|
||||
return;
|
||||
|
||||
printf("pin %d: caps:", pin);
|
||||
if (name != NULL)
|
||||
printf("pin %s: caps:", name);
|
||||
else
|
||||
printf("pin %d: caps:", pin);
|
||||
for (bs = pinflags; bs->string != NULL; bs++)
|
||||
if (ctl.gp_caps & bs->mask)
|
||||
if (set.gp_caps & bs->mask)
|
||||
printf(" %s", bs->string);
|
||||
printf(", flags:");
|
||||
for (bs = pinflags; bs->string != NULL; bs++)
|
||||
if (ctl.gp_flags & bs->mask)
|
||||
if (set.gp_flags & bs->mask)
|
||||
printf(" %s", bs->string);
|
||||
if (fl > 0) {
|
||||
printf(" ->");
|
||||
|
@ -223,13 +298,58 @@ pinctl(int pin, char *flags[], int nflags)
|
|||
printf("\n");
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
gpiounset(int pin, char *name)
|
||||
{
|
||||
struct gpio_set set;
|
||||
|
||||
memset(&set, 0, sizeof(set));
|
||||
if (name != NULL)
|
||||
strlcpy(set.gp_name, name, sizeof(set.gp_name));
|
||||
else
|
||||
set.gp_pin = pin;
|
||||
|
||||
if (ioctl(devfd, GPIOUNSET, &set) == -1)
|
||||
err(EXIT_FAILURE, "GPIOUNSET");
|
||||
}
|
||||
|
||||
void
|
||||
devattach(char *dvname, int offset, u_int32_t mask)
|
||||
{
|
||||
struct gpio_attach attach;
|
||||
|
||||
memset(&attach, 0, sizeof(attach));
|
||||
strlcpy(attach.ga_dvname, dvname, sizeof(attach.ga_dvname));
|
||||
attach.ga_offset = offset;
|
||||
attach.ga_mask = mask;
|
||||
if (ioctl(devfd, GPIOATTACH, &attach) == -1)
|
||||
err(EXIT_FAILURE, "GPIOATTACH");
|
||||
}
|
||||
|
||||
void
|
||||
devdetach(char *dvname)
|
||||
{
|
||||
struct gpio_attach attach;
|
||||
|
||||
memset(&attach, 0, sizeof(attach));
|
||||
strlcpy(attach.ga_dvname, dvname, sizeof(attach.ga_dvname));
|
||||
if (ioctl(devfd, GPIODETACH, &attach) == -1)
|
||||
err(EXIT_FAILURE, "GPIODETACH");
|
||||
}
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr, "usage: %s [-hq] [-d device] [pin] [0 | 1 | 2]\n",
|
||||
getprogname());
|
||||
fprintf(stderr, " %s [-hq] [-d device] -c pin [flags]\n",
|
||||
getprogname());
|
||||
extern char *__progname;
|
||||
|
||||
fprintf(stderr, "usage: %s [-q] device [pin] [0 | 1 | 2 | "
|
||||
"on | off | toggle]\n", __progname);
|
||||
fprintf(stderr, " %s [-q] device pin set [flags] [name]\n",
|
||||
__progname);
|
||||
fprintf(stderr, " %s [-q] device pin unset\n", __progname);
|
||||
fprintf(stderr, " %s [-q] device attach device offset mask\n",
|
||||
__progname);
|
||||
fprintf(stderr, " %s [-q] device detach device\n", __progname);
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
/* $NetBSD: strtonum.c,v 1.1 2009/07/25 16:18:09 mbalmer Exp $ */
|
||||
/* $OpenBSD: strtonum.c,v 1.6 2004/08/03 19:38:01 millert Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2004 Ted Unangst and Todd Miller
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define INVALID 1
|
||||
#define TOOSMALL 2
|
||||
#define TOOLARGE 3
|
||||
|
||||
long long strtonum(const char *numstr, long long minval, long long maxval,
|
||||
const char **errstrp);
|
||||
|
||||
long long
|
||||
strtonum(const char *numstr, long long minval, long long maxval,
|
||||
const char **errstrp)
|
||||
{
|
||||
long long ll = 0;
|
||||
char *ep;
|
||||
int error = 0;
|
||||
struct errval {
|
||||
const char *errstr;
|
||||
int err;
|
||||
} ev[4] = {
|
||||
{ NULL, 0 },
|
||||
{ "invalid", EINVAL },
|
||||
{ "too small", ERANGE },
|
||||
{ "too large", ERANGE },
|
||||
};
|
||||
|
||||
ev[0].err = errno;
|
||||
errno = 0;
|
||||
if (minval > maxval)
|
||||
error = INVALID;
|
||||
else {
|
||||
ll = strtoll(numstr, &ep, 10);
|
||||
if (numstr == ep || *ep != '\0')
|
||||
error = INVALID;
|
||||
else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
|
||||
error = TOOSMALL;
|
||||
else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
|
||||
error = TOOLARGE;
|
||||
}
|
||||
if (errstrp != NULL)
|
||||
*errstrp = ev[error].errstr;
|
||||
errno = ev[error].err;
|
||||
if (error)
|
||||
ll = 0;
|
||||
|
||||
return (ll);
|
||||
}
|
Loading…
Reference in New Issue