summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMarc Balmer <mbalmer@cvs.openbsd.org>2008-11-26 14:51:21 +0000
committerMarc Balmer <mbalmer@cvs.openbsd.org>2008-11-26 14:51:21 +0000
commit8b05f52c66040516db238de1c834b93ee6487452 (patch)
tree070d78fbc63de1a4c1c37ab65095ebdfda855a6c /sys
parent9ba03bd9e7b5805535a5960ff0f76bc3625d8fbd (diff)
Change the semantics of gpio(4) devices by locking down pin
configuration and device attachment/detachment to securelevel 0. GPIO pins can now only be configured at securelevel 0. Once the securelevel is raised, only pins that have been configured and set for securelevel access using the GPIOPINSET ioctl are accessible. This also adds the possibility to give GPIO pins a name. ok uwe@
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/gpio/gpio.c189
-rw-r--r--sys/dev/gpio/gpiovar.h8
-rw-r--r--sys/sys/gpio.h31
3 files changed, 176 insertions, 52 deletions
diff --git a/sys/dev/gpio/gpio.c b/sys/dev/gpio/gpio.c
index 9a910140ba6..d3d602667db 100644
--- a/sys/dev/gpio/gpio.c
+++ b/sys/dev/gpio/gpio.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: gpio.c,v 1.8 2008/11/24 12:12:12 mbalmer Exp $ */
+/* $OpenBSD: gpio.c,v 1.9 2008/11/26 14:51:20 mbalmer Exp $ */
/*
* Copyright (c) 2004, 2006 Alexander Yurchenko <grange@openbsd.org>
@@ -36,12 +36,13 @@
struct gpio_softc {
struct device sc_dev;
- gpio_chipset_tag_t sc_gc; /* our GPIO controller */
- gpio_pin_t *sc_pins; /* pins array */
- int sc_npins; /* total number of pins */
+ gpio_chipset_tag_t sc_gc; /* GPIO controller */
+ gpio_pin_t *sc_pins; /* pins array */
+ int sc_npins; /* number of pins */
int sc_opened;
- LIST_HEAD(, gpio_dev) sc_list;
+ LIST_HEAD(, gpio_dev) sc_devs; /* devices */
+ LIST_HEAD(, gpio_name) sc_names; /* named pins */
};
int gpio_match(struct device *, void *, void *);
@@ -50,6 +51,7 @@ void gpio_attach(struct device *, struct device *, void *);
int gpio_detach(struct device *, int);
int gpio_search(struct device *, void *, void *);
int gpio_print(void *, const char *);
+int gpio_pinbyname(struct gpio_softc *, char *gp_name);
struct cfattach gpio_ca = {
sizeof (struct gpio_softc),
@@ -266,18 +268,30 @@ gpioclose(dev_t dev, int flag, int mode, struct proc *p)
}
int
+gpio_pinbyname(struct gpio_softc *sc, char *gp_name)
+{
+ struct gpio_name *nm;
+
+ LIST_FOREACH(nm, &sc->sc_names, gp_next)
+ if (!strcmp(nm->gp_name, gp_name))
+ return (nm->gp_pin);
+ return (-1);
+}
+
+int
gpioioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
{
struct gpio_softc *sc;
gpio_chipset_tag_t gc;
struct gpio_info *info;
struct gpio_pin_op *op;
- struct gpio_pin_ctl *ctl;
struct gpio_attach *attach;
struct gpio_attach_args ga;
struct gpio_dev *gdev;
+ struct gpio_name *nm;
+ struct gpio_pin_set *set;
struct device *dv;
- int pin, value, flags;
+ int pin, value, flags, npins, found;
sc = (struct gpio_softc *)device_lookup(&gpio_cd, minor(dev));
gc = sc->sc_gc;
@@ -285,16 +299,32 @@ gpioioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
switch (cmd) {
case GPIOINFO:
info = (struct gpio_info *)data;
-
- info->gpio_npins = sc->sc_npins;
+ if (securelevel < 1)
+ info->gpio_npins = sc->sc_npins;
+ else {
+ for (pin = npins = 0; pin < sc->sc_npins; pin++)
+ if (sc->sc_pins[pin].pin_flags & GPIO_PIN_SET)
+ ++npins;
+ info->gpio_npins = npins;
+ }
break;
case GPIOPINREAD:
op = (struct gpio_pin_op *)data;
- pin = op->gp_pin;
+ if (op->gp_name[0] != '\0') {
+ pin = gpio_pinbyname(sc, op->gp_name);
+ if (pin == -1)
+ return (EINVAL);
+ } else
+ pin = op->gp_pin;
+
if (pin < 0 || pin >= sc->sc_npins)
return (EINVAL);
+ if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) &&
+ securelevel > 0)
+ return (EPERM);
+
/* return read value */
op->gp_value = gpiobus_pin_read(gc, pin);
break;
@@ -304,12 +334,23 @@ gpioioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
op = (struct gpio_pin_op *)data;
- pin = op->gp_pin;
+ if (op->gp_name[0] != '\0') {
+ pin = gpio_pinbyname(sc, op->gp_name);
+ if (pin == -1)
+ return (EINVAL);
+ } else
+ pin = op->gp_pin;
+
if (pin < 0 || pin >= sc->sc_npins)
return (EINVAL);
+
if (sc->sc_pins[pin].pin_mapped)
return (EBUSY);
+ if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) &&
+ securelevel > 0)
+ return (EPERM);
+
value = op->gp_value;
if (value != GPIO_PIN_LOW && value != GPIO_PIN_HIGH)
return (EINVAL);
@@ -326,12 +367,23 @@ gpioioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
op = (struct gpio_pin_op *)data;
- pin = op->gp_pin;
+ if (op->gp_name[0] != '\0') {
+ pin = gpio_pinbyname(sc, op->gp_name);
+ if (pin == -1)
+ return (EINVAL);
+ } else
+ pin = op->gp_pin;
+
if (pin < 0 || pin >= sc->sc_npins)
return (EINVAL);
+
if (sc->sc_pins[pin].pin_mapped)
return (EBUSY);
+ if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET) &&
+ securelevel > 0)
+ return (EPERM);
+
value = (sc->sc_pins[pin].pin_state == GPIO_PIN_LOW ?
GPIO_PIN_HIGH : GPIO_PIN_LOW);
gpiobus_pin_write(gc, pin, value);
@@ -340,33 +392,10 @@ gpioioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
/* update current value */
sc->sc_pins[pin].pin_state = value;
break;
- case GPIOPINCTL:
- if ((flag & FWRITE) == 0)
- return (EBADF);
-
- ctl = (struct gpio_pin_ctl *)data;
-
- pin = ctl->gp_pin;
- if (pin < 0 || pin >= sc->sc_npins)
- return (EINVAL);
- if (sc->sc_pins[pin].pin_mapped)
- return (EBUSY);
-
- flags = ctl->gp_flags;
- /* check that the controller supports all requested flags */
- if ((flags & sc->sc_pins[pin].pin_caps) != flags)
- return (ENODEV);
-
- ctl->gp_caps = sc->sc_pins[pin].pin_caps;
- /* return old value */
- ctl->gp_flags = sc->sc_pins[pin].pin_flags;
- if (flags > 0) {
- gpiobus_pin_ctl(gc, pin, flags);
- /* update current value */
- sc->sc_pins[pin].pin_flags = flags;
- }
- break;
case GPIOATTACH:
+ if (securelevel > 0)
+ return (EPERM);
+
attach = (struct gpio_attach *)data;
bzero(&ga, sizeof(ga));
ga.ga_gpio = sc;
@@ -379,12 +408,15 @@ gpioioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
gdev = malloc(sizeof(struct gpio_dev), M_DEVBUF,
M_WAITOK);
gdev->sc_dev = dv;
- LIST_INSERT_HEAD(&sc->sc_list, gdev, sc_next);
+ LIST_INSERT_HEAD(&sc->sc_devs, gdev, sc_next);
}
break;
case GPIODETACH:
+ if (securelevel > 0)
+ return (EPERM);
+
attach = (struct gpio_attach *)data;
- LIST_FOREACH(gdev, &sc->sc_list, sc_next) {
+ LIST_FOREACH(gdev, &sc->sc_devs, sc_next) {
if (strcmp(gdev->sc_dev->dv_xname, attach->ga_dvname)
== 0) {
if (config_detach(gdev->sc_dev, 0) == 0) {
@@ -395,6 +427,83 @@ gpioioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
}
}
break;
+ case GPIOPINSET:
+ if (securelevel > 0)
+ return (EPERM);
+
+ set = (struct gpio_pin_set *)data;
+
+ if (set->gp_name[0] != '\0') {
+ pin = gpio_pinbyname(sc, set->gp_name);
+ if (pin == -1)
+ return (EINVAL);
+ } else
+ pin = set->gp_pin;
+ if (pin < 0 || pin >= sc->sc_npins)
+ return (EINVAL);
+ flags = set->gp_flags;
+ /* check that the controller supports all requested flags */
+ if ((flags & sc->sc_pins[pin].pin_caps) != flags)
+ return (ENODEV);
+ flags = set->gp_flags | GPIO_PIN_SET;
+
+ set->gp_caps = sc->sc_pins[pin].pin_caps;
+ /* return old value */
+ set->gp_flags = sc->sc_pins[pin].pin_flags;
+ if (flags > 0) {
+ gpiobus_pin_ctl(gc, pin, flags);
+ /* update current value */
+ sc->sc_pins[pin].pin_flags = flags;
+ }
+
+ /* rename pin or new pin? */
+ if (set->gp_name2[0] != '\0') {
+ found = 0;
+ LIST_FOREACH(nm, &sc->sc_names, gp_next)
+ if (nm->gp_pin == pin) {
+ strlcpy(nm->gp_name, set->gp_name2,
+ sizeof(nm->gp_name));
+ found = 1;
+ break;
+ }
+ if (!found) {
+ nm = malloc(sizeof(struct gpio_name),
+ M_DEVBUF, M_WAITOK);
+ strlcpy(nm->gp_name, set->gp_name2,
+ sizeof(nm->gp_name));
+ nm->gp_pin = set->gp_pin;
+ LIST_INSERT_HEAD(&sc->sc_names, nm, gp_next);
+ }
+ }
+ break;
+ case GPIOPINUNSET:
+ if (securelevel > 0)
+ return (EPERM);
+
+ set = (struct gpio_pin_set *)data;
+ if (set->gp_name[0] != '\0') {
+ pin = gpio_pinbyname(sc, set->gp_name);
+ if (pin == -1)
+ return (EINVAL);
+ } else
+ pin = set->gp_pin;
+
+ if (pin < 0 || pin >= sc->sc_npins)
+ return (EINVAL);
+ if (sc->sc_pins[pin].pin_mapped)
+ return (EBUSY);
+ if (!(sc->sc_pins[pin].pin_flags & GPIO_PIN_SET))
+ return (EINVAL);
+
+ LIST_FOREACH(nm, &sc->sc_names, gp_next) {
+ if (nm->gp_pin == pin) {
+ LIST_REMOVE(nm, gp_next);
+ free(nm, M_DEVBUF);
+ break;
+ }
+ }
+ sc->sc_pins[pin].pin_flags &= ~GPIO_PIN_SET;
+ break;
default:
return (ENOTTY);
}
diff --git a/sys/dev/gpio/gpiovar.h b/sys/dev/gpio/gpiovar.h
index b507370ebe2..8987ae7d1e6 100644
--- a/sys/dev/gpio/gpiovar.h
+++ b/sys/dev/gpio/gpiovar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: gpiovar.h,v 1.4 2008/11/24 12:12:12 mbalmer Exp $ */
+/* $OpenBSD: gpiovar.h,v 1.5 2008/11/26 14:51:20 mbalmer Exp $ */
/*
* Copyright (c) 2004, 2006 Alexander Yurchenko <grange@openbsd.org>
@@ -74,6 +74,12 @@ struct gpio_dev {
LIST_ENTRY(gpio_dev) sc_next;
};
+struct gpio_name {
+ char gp_name[GPIOPINMAXNAME];
+ int gp_pin;
+ LIST_ENTRY(gpio_name) gp_next;
+};
+
int gpio_pin_map(void *, int, u_int32_t, struct gpio_pinmap *);
void gpio_pin_unmap(void *, struct gpio_pinmap *);
int gpio_pin_read(void *, struct gpio_pinmap *, int);
diff --git a/sys/sys/gpio.h b/sys/sys/gpio.h
index b580f712d43..6bfbea316db 100644
--- a/sys/sys/gpio.h
+++ b/sys/sys/gpio.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: gpio.h,v 1.6 2008/11/24 13:22:53 mbalmer Exp $ */
+/* $OpenBSD: gpio.h,v 1.7 2008/11/26 14:51:20 mbalmer Exp $ */
/*
* Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org>
*
@@ -22,6 +22,9 @@
#define GPIO_PIN_LOW 0x00 /* low level (logical 0) */
#define GPIO_PIN_HIGH 0x01 /* high level (logical 1) */
+/* Max name length of a pin */
+#define GPIOPINMAXNAME 64
+
/* GPIO pin configuration flags */
#define GPIO_PIN_INPUT 0x0001 /* input direction */
#define GPIO_PIN_OUTPUT 0x0002 /* output direction */
@@ -33,6 +36,8 @@
#define GPIO_PIN_PULLDOWN 0x0080 /* internal pull-down enabled */
#define GPIO_PIN_INVIN 0x0100 /* invert input */
#define GPIO_PIN_INVOUT 0x0200 /* invert output */
+#define GPIO_PIN_USER 0x0400 /* user != 0 can access */
+#define GPIO_PIN_SET 0x8000 /* set for securelevel access */
/* GPIO controller description */
struct gpio_info {
@@ -41,15 +46,18 @@ struct gpio_info {
/* GPIO pin operation (read/write/toggle) */
struct gpio_pin_op {
- int gp_pin; /* pin number */
- int gp_value; /* value */
+ char gp_name[GPIOPINMAXNAME]; /* pin name */
+ int gp_pin; /* pin number */
+ int gp_value; /* value */
};
-/* GPIO pin control */
-struct gpio_pin_ctl {
- int gp_pin; /* pin number */
- int gp_caps; /* pin capabilities (read-only) */
- int gp_flags; /* pin configuration flags */
+/* GPIO pin configuration */
+struct gpio_pin_set {
+ char gp_name[GPIOPINMAXNAME];
+ int gp_pin;
+ int gp_caps;
+ int gp_flags;
+ char gp_name2[GPIOPINMAXNAME]; /* new name */
};
/* Attach/detach device drivers that use GPIO pins */
@@ -63,8 +71,9 @@ struct gpio_attach {
#define GPIOPINREAD _IOWR('G', 1, struct gpio_pin_op)
#define GPIOPINWRITE _IOWR('G', 2, struct gpio_pin_op)
#define GPIOPINTOGGLE _IOWR('G', 3, struct gpio_pin_op)
-#define GPIOPINCTL _IOWR('G', 4, struct gpio_pin_ctl)
-#define GPIOATTACH _IOWR('G', 5, struct gpio_attach)
-#define GPIODETACH _IOWR('G', 6, struct gpio_attach)
+#define GPIOPINSET _IOWR('G', 4, struct gpio_pin_set)
+#define GPIOPINUNSET _IOWR('G', 5, struct gpio_pin_set)
+#define GPIOATTACH _IOWR('G', 6, struct gpio_attach)
+#define GPIODETACH _IOWR('G', 7, struct gpio_attach)
#endif /* !_SYS_GPIO_H_ */