Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src Add a new ioctl, GPIOPULSE to gpio(4) to allow for pulsing a...
details: https://anonhg.NetBSD.org/src/rev/bb38c0047fb5
branches: trunk
changeset: 768863:bb38c0047fb5
user: mbalmer <mbalmer%NetBSD.org@localhost>
date: Sun Aug 28 07:48:50 2011 +0000
description:
Add a new ioctl, GPIOPULSE to gpio(4) to allow for pulsing a pin.
If a pin can pulse in hardware, that will be used, else it will
be pulsed in software. There is no way yet to set the pulse frequency
for pins that pulse in hardware. While here, make the code mpsafe and
allow more than one thread in the driver (access to ioctl is serialized).
diffstat:
share/man/man4/gpio.4 | 29 +++++-
sys/dev/gpio/gpio.c | 231 ++++++++++++++++++++++++++++++++++----------
sys/dev/gpio/gpiovar.h | 32 +++--
sys/sys/gpio.h | 40 +++++--
usr.sbin/gpioctl/gpioctl.8 | 29 ++++-
usr.sbin/gpioctl/gpioctl.c | 95 ++++++++++++++++--
6 files changed, 356 insertions(+), 100 deletions(-)
diffs (truncated from 917 to 300 lines):
diff -r 49a3e00d954d -r bb38c0047fb5 share/man/man4/gpio.4
--- a/share/man/man4/gpio.4 Sun Aug 28 07:48:18 2011 +0000
+++ b/share/man/man4/gpio.4 Sun Aug 28 07:48:50 2011 +0000
@@ -1,4 +1,4 @@
-.\" $NetBSD: gpio.4,v 1.18 2010/03/22 18:58:31 joerg Exp $
+.\" $NetBSD: gpio.4,v 1.19 2011/08/28 07:48:50 mbalmer Exp $
.\" $OpenBSD: gpio.4,v 1.5 2004/11/23 09:39:29 reyk Exp $
.\"
.\" Copyright (c) 2004 Alexander Yurchenko <grange%openbsd.org@localhost>
@@ -15,7 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd September 27, 2009
+.Dd August 21, 2011
.Dt GPIO 4
.Os
.Sh NAME
@@ -123,6 +123,31 @@
.Fa gp_value
field is ignored and on return contains the old pin state.
.Pp
+.It Dv GPIOPULSE (struct gpio_pulse)
+Starts pulsing the pin:
+.Bd -literal
+/* GPIO pulse request */
+struct gpio_pulse {
+ char gp_name[GPIOMAXNAME]; /* pin name */
+ int gp_pin; /* pin number */
+ struct timeval gp_pulse_on; /* "on" period */
+ struct timeval gp_pulse_off; /* "off" period */
+};
+.Ed
+.Pp
+The
+.Fa gp_name
+or
+.Fa gp_pin
+field must be set before calling.
+If
+.Fa gp_pulse_on
+or
+.Fa gp_pulse_off
+is set to zero, a default of
+.Xr hz 9 / 2
+is assumed for both periods.
+.Pp
.It Dv GPIOSET (struct gpio_set)
Changes pin configuration flags with the new ones provided in the
.Fa gpio_set
diff -r 49a3e00d954d -r bb38c0047fb5 sys/dev/gpio/gpio.c
--- a/sys/dev/gpio/gpio.c Sun Aug 28 07:48:18 2011 +0000
+++ b/sys/dev/gpio/gpio.c Sun Aug 28 07:48:50 2011 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: gpio.c,v 1.35 2011/08/12 08:00:52 mbalmer Exp $ */
+/* $NetBSD: gpio.c,v 1.36 2011/08/28 07:48:50 mbalmer Exp $ */
/* $OpenBSD: gpio.c,v 1.6 2006/01/14 12:33:49 grange Exp $ */
/*
@@ -19,21 +19,25 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: gpio.c,v 1.35 2011/08/12 08:00:52 mbalmer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: gpio.c,v 1.36 2011/08/28 07:48:50 mbalmer Exp $");
/*
* General Purpose Input/Output framework.
*/
#include <sys/param.h>
+#include <sys/callout.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/device.h>
#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <sys/gpio.h>
+#include <sys/kernel.h>
#include <sys/vnode.h>
#include <sys/kmem.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
#include <sys/queue.h>
#include <sys/kauth.h>
#ifdef _MODULE
@@ -58,7 +62,9 @@
gpio_pin_t *sc_pins; /* pins array */
int sc_npins; /* number of pins */
- int sc_opened;
+ kmutex_t sc_mtx;
+ kcondvar_t sc_ioctl; /* ioctl in progress */
+ int sc_ioctl_busy; /* ioctl is busy */
LIST_HEAD(, gpio_dev) sc_devs; /* devices */
LIST_HEAD(, gpio_name) sc_names; /* named pins */
};
@@ -73,6 +79,9 @@
static int gpio_search(device_t, cfdata_t, const int *, void *);
static int gpio_print(void *, const char *);
static int gpio_pinbyname(struct gpio_softc *, char *);
+static void gpio_pulse(void *);
+static int gpio_ioctl(struct gpio_softc *, u_long, void *, int,
+ struct lwp *);
/* Old API */
static int gpio_ioctl_oapi(struct gpio_softc *, u_long, void *, int,
@@ -85,10 +94,11 @@
dev_type_open(gpioopen);
dev_type_close(gpioclose);
dev_type_ioctl(gpioioctl);
+dev_type_ioctl(gpioioctl_locked);
const struct cdevsw gpio_cdevsw = {
gpioopen, gpioclose, noread, nowrite, gpioioctl,
- nostop, notty, nopoll, nommap, nokqfilter, D_OTHER,
+ nostop, notty, nopoll, nommap, nokqfilter, D_OTHER | D_MPSAFE
};
extern struct cfdriver gpio_cd;
@@ -144,7 +154,7 @@
{
struct gpio_softc *sc = device_private(self);
struct gpiobus_attach_args *gba = aux;
-
+ int pin;
sc->sc_dev = self;
sc->sc_gc = gba->gba_gc;
sc->sc_pins = gba->gba_pins;
@@ -152,8 +162,15 @@
printf(": %d pins\n", sc->sc_npins);
+ for (pin = 0; pin < sc->sc_npins; pin++) {
+ callout_init(&sc->sc_pins[pin].pin_pulse, CALLOUT_MPSAFE);
+ callout_setfunc(&sc->sc_pins[pin].pin_pulse, gpio_pulse,
+ &sc->sc_pins[pin]);
+ }
if (!pmf_device_register(self, NULL, gpio_resume))
aprint_error_dev(self, "couldn't establish power handler\n");
+ mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_VM);
+ cv_init(&sc->sc_ioctl, "gpioctl");
/*
* Attach all devices that can be connected to the GPIO pins
@@ -165,11 +182,23 @@
static int
gpio_detach(device_t self, int flags)
{
- int rc;
+ struct gpio_softc *sc;
+ int pin, rc;
+
+ sc = device_private(self);
+
+ for (pin = 0; pin < sc->sc_npins; pin++) {
+ if (sc->sc_pins[pin].pin_state & GPIO_PIN_PULSE) {
+ callout_halt(&sc->sc_pins[pin].pin_pulse, NULL);
+ callout_destroy(&sc->sc_pins[pin].pin_pulse);
+ sc->sc_pins[pin].pin_state &= ~GPIO_PIN_PULSE;
+ }
+ }
if ((rc = config_detach_children(self, flags)) != 0)
return rc;
-
+ mutex_destroy(&sc->sc_mtx);
+ cv_destroy(&sc->sc_ioctl);
#if 0
int maj, mn;
@@ -228,7 +257,7 @@
/* return 1 if all pins can be mapped, 0 if not */
int
-gpio_pin_can_map(void *gpio, int offset, u_int32_t mask)
+gpio_pin_can_map(void *gpio, int offset, uint32_t mask)
{
struct gpio_softc *sc = gpio;
int npins, pin, i;
@@ -250,7 +279,7 @@
}
int
-gpio_pin_map(void *gpio, int offset, u_int32_t mask, struct gpio_pinmap *map)
+gpio_pin_map(void *gpio, int offset, uint32_t mask, struct gpio_pinmap *map)
{
struct gpio_softc *sc = gpio;
int npins, pin, i;
@@ -320,7 +349,7 @@
}
int
-gpio_npins(u_int32_t mask)
+gpio_npins(uint32_t mask)
{
int npins, i;
@@ -332,30 +361,47 @@
}
int
+gpio_lock(void *data)
+{
+ struct gpio_softc *sc;
+ int error;
+
+ error = 0;
+ sc = (struct gpio_softc *)data;
+ mutex_enter(&sc->sc_mtx);
+ while (sc->sc_ioctl_busy) {
+ error = cv_wait_sig(&sc->sc_ioctl, &sc->sc_mtx);
+ if (error)
+ break;
+ }
+ if (!error)
+ sc->sc_ioctl_busy = 1;
+ mutex_exit(&sc->sc_mtx);
+ return error;
+}
+
+void
+gpio_unlock(void *data)
+{
+ struct gpio_softc *sc;
+
+ sc = (struct gpio_softc *)data;
+ mutex_enter(&sc->sc_mtx);
+ sc->sc_ioctl_busy = 0;
+ cv_signal(&sc->sc_ioctl);
+ mutex_exit(&sc->sc_mtx);
+}
+
+int
gpioopen(dev_t dev, int flag, int mode, struct lwp *l)
{
struct gpio_softc *sc;
- int ret;
sc = device_lookup_private(&gpio_cd, minor(dev));
if (sc == NULL)
return ENXIO;
- DPRINTF(("%s: opening\n", device_xname(sc->sc_dev)));
- if (sc->sc_opened) {
- DPRINTF(("%s: already opened\n", device_xname(sc->sc_dev)));
- return EBUSY;
- }
- if ((ret = gpiobus_open(sc->sc_gc, sc->sc_dev))) {
- DPRINTF(("%s: gpiobus_open returned %d\n",
- device_xname(sc->sc_dev),
- ret));
- return ret;
- }
-
- sc->sc_opened = 1;
-
- return 0;
+ return gpiobus_open(sc->sc_gc, sc->sc_dev);
}
int
@@ -364,10 +410,7 @@
struct gpio_softc *sc;
sc = device_lookup_private(&gpio_cd, minor(dev));
- DPRINTF(("%s: closing\n", device_xname(sc->sc_dev)));
- (void)gpiobus_close(sc->sc_gc, sc->sc_dev);
- sc->sc_opened = 0;
-
+ gpiobus_close(sc->sc_gc, sc->sc_dev);
return 0;
}
@@ -382,25 +425,63 @@
return -1;
}
+static void
+gpio_pulse(void *arg)
+{
+ struct gpio_pin *pin;
+
+ pin = (struct gpio_pin *)arg;
+ if ((pin->pin_state & GPIO_PIN_PULSE) == 0)
+ return;
+
+ if (pin->pin_state & GPIO_PIN_HIGH) {
+ gpiobus_pin_write(pin->pin_gc, pin->pin_num, GPIO_PIN_LOW);
+ pin->pin_state &= ~GPIO_PIN_HIGH;
+ callout_schedule(&pin->pin_pulse, pin->pin_ticks_off);
+ } else {
+ gpiobus_pin_write(pin->pin_gc, pin->pin_num, GPIO_PIN_HIGH);
+ pin->pin_state |= GPIO_PIN_HIGH;
+ callout_schedule(&pin->pin_pulse, pin->pin_ticks_on);
+ }
+}
+
int
gpioioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
Home |
Main Index |
Thread Index |
Old Index