[PATCH 02/12] drivers/gpio: provide optional timestamped readouts

Philippe Gerum rpm at xenomai.org
Thu Jan 24 16:34:18 CET 2019


In timestamping mode, read() returns the timestamp of the latest event
receipt on the pin based on CLOCK_MONOTONIC, along with the pin
state. This is an optional pin readout mode controlled by the
GPIO_RTIOC_TS request, e.g.:

struct rtdm_gpio_readout rdo;
int ret, on, val;

on = 1;
ret = ioctl(pinfd, GPIO_RTIOC_TS, &on);
ret = read(pinfd, &rdo, sizeof(rdo));
/* pin state changed to rdo.value at time rdo.timestamp */

on = 0;
ret = ioctl(pinfd, GPIO_RTIOC_TS, &on);
ret = read(pinfd, &val, sizeof(val));
/* pin state changed to value (time of change unspecified) */

By default, timestamping mode is disabled, which corresponds to the
original behavior.

Signed-off-by: Philippe Gerum <rpm at xenomai.org>
---
 include/cobalt/kernel/rtdm/gpio.h |  1 +
 include/rtdm/uapi/gpio.h          | 18 +++++++----
 kernel/drivers/gpio/gpio-core.c   | 54 +++++++++++++++++++++++--------
 3 files changed, 54 insertions(+), 19 deletions(-)

diff --git a/include/cobalt/kernel/rtdm/gpio.h b/include/cobalt/kernel/rtdm/gpio.h
index cdb472f8a..00055ec0a 100644
--- a/include/cobalt/kernel/rtdm/gpio.h
+++ b/include/cobalt/kernel/rtdm/gpio.h
@@ -33,6 +33,7 @@ struct rtdm_gpio_pin {
 	rtdm_event_t event;
 	char *name;
 	struct gpio_desc *desc;
+	nanosecs_abs_t timestamp;
 };
 
 struct rtdm_gpio_chip {
diff --git a/include/rtdm/uapi/gpio.h b/include/rtdm/uapi/gpio.h
index b745f156c..ac14be66c 100644
--- a/include/rtdm/uapi/gpio.h
+++ b/include/rtdm/uapi/gpio.h
@@ -18,12 +18,18 @@
 #ifndef _RTDM_UAPI_GPIO_H
 #define _RTDM_UAPI_GPIO_H
 
-#define GPIO_RTIOC_DIR_OUT		_IOW(RTDM_CLASS_GPIO, 0, int)
-#define GPIO_RTIOC_DIR_IN		_IO(RTDM_CLASS_GPIO, 1)
-#define GPIO_RTIOC_IRQEN		_IOW(RTDM_CLASS_GPIO, 2, int) /* GPIO trigger */
-#define GPIO_RTIOC_IRQDIS		_IO(RTDM_CLASS_GPIO, 3)
-#define GPIO_RTIOC_REQS                _IO(RTDM_CLASS_GPIO, 4)
-#define GPIO_RTIOC_RELS                _IO(RTDM_CLASS_GPIO, 5)
+struct rtdm_gpio_readout {
+	__u64 timestamp;
+	__s32 value;
+};
+
+#define GPIO_RTIOC_DIR_OUT	_IOW(RTDM_CLASS_GPIO, 0, int)
+#define GPIO_RTIOC_DIR_IN	_IO(RTDM_CLASS_GPIO, 1)
+#define GPIO_RTIOC_IRQEN	_IOW(RTDM_CLASS_GPIO, 2, int) /* GPIO trigger */
+#define GPIO_RTIOC_IRQDIS	_IO(RTDM_CLASS_GPIO, 3)
+#define GPIO_RTIOC_REQS		_IO(RTDM_CLASS_GPIO, 4)
+#define GPIO_RTIOC_RELS		_IO(RTDM_CLASS_GPIO, 5)
+#define GPIO_RTIOC_TS		_IOR(RTDM_CLASS_GPIO, 7, int)
 
 #define GPIO_TRIGGER_NONE		0x0 /* unspecified */
 #define GPIO_TRIGGER_EDGE_RISING	0x1
diff --git a/kernel/drivers/gpio/gpio-core.c b/kernel/drivers/gpio/gpio-core.c
index 3ce73dbd5..81f9653f1 100644
--- a/kernel/drivers/gpio/gpio-core.c
+++ b/kernel/drivers/gpio/gpio-core.c
@@ -28,7 +28,8 @@ struct rtdm_gpio_chan {
 	int requested : 1,
 		has_direction : 1,
 		is_output : 1,
-		is_interrupt : 1;
+	        is_interrupt : 1,
+		want_timestamp : 1;
 };
 
 static LIST_HEAD(rtdm_gpio_chips);
@@ -41,6 +42,7 @@ static int gpio_pin_interrupt(rtdm_irq_t *irqh)
 
 	pin = rtdm_irq_get_arg(irqh, struct rtdm_gpio_pin);
 
+	pin->timestamp = rtdm_clock_read_monotonic();
 	rtdm_event_signal(&pin->event);
 
 	return RTDM_IRQ_HANDLED;
@@ -187,6 +189,12 @@ static int gpio_pin_ioctl_nrt(struct rtdm_fd *fd,
 		gpio_free(gpio);
 		chan->requested = false;
 		break;
+	case GPIO_RTIOC_TS:
+		ret = rtdm_safe_copy_from_user(fd, &val, arg, sizeof(val));
+		if (ret)
+			return ret;
+		chan->want_timestamp = !!val;
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -199,11 +207,9 @@ static ssize_t gpio_pin_read_rt(struct rtdm_fd *fd,
 {
 	struct rtdm_gpio_chan *chan = rtdm_fd_to_private(fd);
 	struct rtdm_device *dev = rtdm_fd_device(fd);
+	struct rtdm_gpio_readout rdo;
 	struct rtdm_gpio_pin *pin;
-	int value, ret;
-
-	if (len < sizeof(value))
-		return -EINVAL;
+	int ret;
 
 	if (!chan->has_direction)
 		return -EAGAIN;
@@ -213,16 +219,37 @@ static ssize_t gpio_pin_read_rt(struct rtdm_fd *fd,
 
 	pin = container_of(dev, struct rtdm_gpio_pin, dev);
 
-	if (!(fd->oflags & O_NONBLOCK)) {
-		ret = rtdm_event_wait(&pin->event);
-		if (ret)
-			return ret;
-	}
+	if (chan->want_timestamp) {
+		if (len < sizeof(rdo))
+			return -EINVAL;
+
+		if (!(fd->oflags & O_NONBLOCK)) {
+			ret = rtdm_event_wait(&pin->event);
+			if (ret)
+				return ret;
+			rdo.timestamp = pin->timestamp;
+		} else
+			rdo.timestamp = rtdm_clock_read_monotonic();
+
+		len = sizeof(rdo);
+		rdo.value = gpiod_get_raw_value(pin->desc);
+		ret = rtdm_safe_copy_to_user(fd, buf, &rdo, len);
+	} else {
+		if (len < sizeof(rdo.value))
+			return -EINVAL;
 
-	value = gpiod_get_raw_value(pin->desc);
-	ret = rtdm_safe_copy_to_user(fd, buf, &value, sizeof(value));
+		if (!(fd->oflags & O_NONBLOCK)) {
+			ret = rtdm_event_wait(&pin->event);
+			if (ret)
+				return ret;
+		}
+
+		len = sizeof(rdo.value);
+		rdo.value = gpiod_get_raw_value(pin->desc);
+		ret = rtdm_safe_copy_to_user(fd, buf, &rdo.value, len);
+	}
 	
-	return ret ?: sizeof(value);
+	return ret ?: len;
 }
 
 static ssize_t gpio_pin_write_rt(struct rtdm_fd *fd,
@@ -462,6 +489,7 @@ int rtdm_gpiochip_post_event(struct rtdm_gpio_chip *rgc,
 		return -EINVAL;
 
 	pin = rgc->pins + offset;
+	pin->timestamp = rtdm_clock_read_monotonic();
 	rtdm_event_signal(&pin->event);
 	
 	return 0;
-- 
2.17.2




More information about the Xenomai mailing list