<p>laforge has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-ccid-firmware/+/15691">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">'cuart' Card-UART abstraction + driver for simple serial reader<br><br>Change-Id: Ic7e324d99f78b3bfb98fc667d9a1b7fa363f092d<br>---<br>M ccid/Makefile<br>A ccid/cuart.c<br>A ccid/cuart.h<br>A ccid/cuart_driver_tty.c<br>A ccid/cuart_test.c<br>A ccid/utils_ringbuffer.c<br>A ccid/utils_ringbuffer.h<br>7 files changed, 833 insertions(+), 1 deletion(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-ccid-firmware refs/changes/91/15691/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/ccid/Makefile b/ccid/Makefile</span><br><span>index 5f784ba..a0d6952 100644</span><br><span>--- a/ccid/Makefile</span><br><span>+++ b/ccid/Makefile</span><br><span>@@ -1,13 +1,18 @@</span><br><span> CFLAGS=-Wall -g</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+all: ccid_functionfs hub_functionfs cuart_test</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> ccid_functionfs: ccid_main_functionfs.o logging.o ccid_proto.o ccid_device.o ccid_slot_sim.o</span><br><span>  $(CC) $(CFLAGS) -o $@ $^ -lasan -losmocore -ltalloc -laio</span><br><span> </span><br><span> hub_functionfs: hub_main_functionfs.o</span><br><span>       $(CC) $(CFLAGS) -o $@ $^ -lasan -losmocore -ltalloc -laio</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+cuart_test: cuart_test.o cuart.o cuart_driver_tty.o utils_ringbuffer.o</span><br><span style="color: hsl(120, 100%, 40%);">+ $(CC) $(CFLAGS) -o $@ $^ -lasan -losmocore -ltalloc</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> %.o: %.c</span><br><span>    $(CC) $(CFLAGS) -o $@ -c $^</span><br><span> </span><br><span> clean:</span><br><span style="color: hsl(0, 100%, 40%);">-       rm ccid_functionfs *.o</span><br><span style="color: hsl(120, 100%, 40%);">+        rm ccid_functionfs hub_functionfs cuart_test *.o</span><br><span>diff --git a/ccid/cuart.c b/ccid/cuart.c</span><br><span>new file mode 100644</span><br><span>index 0000000..2c0428e</span><br><span>--- /dev/null</span><br><span>+++ b/ccid/cuart.c</span><br><span>@@ -0,0 +1,133 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <string.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/linuxlist.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "cuart.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static LLIST_HEAD(g_cuart_drivers);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const struct value_string card_uart_event_vals[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_VALUE_STRING(CUART_E_RX_SINGLE),</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_VALUE_STRING(CUART_E_RX_COMPLETE),</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_VALUE_STRING(CUART_E_RX_TIMEOUT),</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_VALUE_STRING(CUART_E_TX_COMPLETE),</span><br><span style="color: hsl(120, 100%, 40%);">+       { 0, NULL }</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct card_uart_driver *cuart_drv_by_name(const char *driver_name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct card_uart_driver *drv;</span><br><span style="color: hsl(120, 100%, 40%);">+ llist_for_each_entry(drv, &g_cuart_drivers, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+               if (!strcmp(drv->name, driver_name))</span><br><span style="color: hsl(120, 100%, 40%);">+                       return drv;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int card_uart_open(struct card_uart *cuart, const char *driver_name, const char *device_name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct card_uart_driver *drv = cuart_drv_by_name(driver_name);</span><br><span style="color: hsl(120, 100%, 40%);">+        int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!drv)</span><br><span style="color: hsl(120, 100%, 40%);">+             return -ENODEV;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     cuart->rx_enabled = true;</span><br><span style="color: hsl(120, 100%, 40%);">+  cuart->rx_threshold = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = drv->ops->open(cuart, device_name);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  cuart->driver = drv;</span><br><span style="color: hsl(120, 100%, 40%);">+       return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int card_uart_close(struct card_uart *cuart)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(cuart);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(cuart->driver);</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(cuart->driver->ops);</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(cuart->driver->ops->close);</span><br><span style="color: hsl(120, 100%, 40%);">+      return cuart->driver->ops->close(cuart);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int card_uart_ctrl(struct card_uart *cuart, enum card_uart_ctl ctl, bool enable)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(cuart);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(cuart->driver);</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(cuart->driver->ops);</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(cuart->driver->ops->ctrl);</span><br><span style="color: hsl(120, 100%, 40%);">+       rc = cuart->driver->ops->ctrl(cuart, ctl, enable);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  switch (ctl) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case CUART_CTL_RX:</span><br><span style="color: hsl(120, 100%, 40%);">+            cuart->rx_enabled = enable;</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int card_uart_tx(struct card_uart *cuart, const uint8_t *data, size_t len, bool rx_after_complete)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(cuart);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(cuart->driver);</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(cuart->driver->ops);</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(cuart->driver->ops->async_tx);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(!cuart->tx_busy);</span><br><span style="color: hsl(120, 100%, 40%);">+      cuart->tx_busy = true;</span><br><span style="color: hsl(120, 100%, 40%);">+     /* disable receiver to avoid receiving what we transmit */</span><br><span style="color: hsl(120, 100%, 40%);">+    card_uart_ctrl(cuart, CUART_CTL_RX, false);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return cuart->driver->ops->async_tx(cuart, data, len, rx_after_complete);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int card_uart_rx(struct card_uart *cuart, uint8_t *data, size_t len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(cuart);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(cuart->driver);</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(cuart->driver->ops);</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(cuart->driver->ops->async_rx);</span><br><span style="color: hsl(120, 100%, 40%);">+   return cuart->driver->ops->async_rx(cuart, data, len);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void card_uart_set_rx_threshold(struct card_uart *cuart, size_t rx_threshold)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        cuart->rx_threshold = rx_threshold;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void card_uart_notification(struct card_uart *cuart, enum card_uart_event evt, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(cuart);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(cuart->handle_event);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        switch (evt) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case CUART_E_TX_COMPLETE:</span><br><span style="color: hsl(120, 100%, 40%);">+             cuart->tx_busy = false;</span><br><span style="color: hsl(120, 100%, 40%);">+            /* re-enable receiver if we're done with transmit */</span><br><span style="color: hsl(120, 100%, 40%);">+              sleep(1);</span><br><span style="color: hsl(120, 100%, 40%);">+             card_uart_ctrl(cuart, CUART_CTL_RX, true);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   cuart->handle_event(cuart, evt, data);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int card_uart_driver_register(struct card_uart_driver *drv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(!cuart_drv_by_name(drv->name));</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(drv->name);</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(drv->ops);</span><br><span style="color: hsl(120, 100%, 40%);">+     llist_add_tail(&drv->list, &g_cuart_drivers);</span><br><span style="color: hsl(120, 100%, 40%);">+      return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/ccid/cuart.h b/ccid/cuart.h</span><br><span>new file mode 100644</span><br><span>index 0000000..7e217db</span><br><span>--- /dev/null</span><br><span>+++ b/ccid/cuart.h</span><br><span>@@ -0,0 +1,107 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdbool.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/linuxlist.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/select.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include "utils_ringbuffer.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum card_uart_event {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* a single byte was received, it's present at the (uint8_t *) data location */</span><br><span style="color: hsl(120, 100%, 40%);">+   CUART_E_RX_SINGLE,</span><br><span style="color: hsl(120, 100%, 40%);">+    /* an entire block of data was received */</span><br><span style="color: hsl(120, 100%, 40%);">+    CUART_E_RX_COMPLETE,</span><br><span style="color: hsl(120, 100%, 40%);">+  CUART_E_RX_TIMEOUT,</span><br><span style="color: hsl(120, 100%, 40%);">+   /* an entire block of data was written, as instructed in prior card_uart_tx() call */</span><br><span style="color: hsl(120, 100%, 40%);">+ CUART_E_TX_COMPLETE,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern const struct value_string card_uart_event_vals[];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum card_uart_ctl {</span><br><span style="color: hsl(120, 100%, 40%);">+  CUART_CTL_RX,</span><br><span style="color: hsl(120, 100%, 40%);">+ CUART_CTL_POWER,</span><br><span style="color: hsl(120, 100%, 40%);">+      CUART_CTL_CLOCK,</span><br><span style="color: hsl(120, 100%, 40%);">+      CUART_CTL_RST,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct card_uart;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct card_uart_ops {</span><br><span style="color: hsl(120, 100%, 40%);">+     int (*open)(struct card_uart *cuart, const char *device_name);</span><br><span style="color: hsl(120, 100%, 40%);">+        int (*close)(struct card_uart *cuart);</span><br><span style="color: hsl(120, 100%, 40%);">+        int (*async_tx)(struct card_uart *cuart, const uint8_t *data, size_t len, bool rx_after_complete);</span><br><span style="color: hsl(120, 100%, 40%);">+    int (*async_rx)(struct card_uart *cuart, uint8_t *data, size_t len);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        int (*ctrl)(struct card_uart *cuart, enum card_uart_ctl ctl, bool enable);</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Card UART driver */</span><br><span style="color: hsl(120, 100%, 40%);">+struct card_uart_driver {</span><br><span style="color: hsl(120, 100%, 40%);">+   /* global list of card UART drivers */</span><br><span style="color: hsl(120, 100%, 40%);">+        struct llist_head list;</span><br><span style="color: hsl(120, 100%, 40%);">+       /* human-readable name of driver */</span><br><span style="color: hsl(120, 100%, 40%);">+   const char *name;</span><br><span style="color: hsl(120, 100%, 40%);">+     /* operations implementing the driver */</span><br><span style="color: hsl(120, 100%, 40%);">+      const struct card_uart_ops *ops;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct card_uart {</span><br><span style="color: hsl(120, 100%, 40%);">+    /* member in global list of UARTs */</span><br><span style="color: hsl(120, 100%, 40%);">+  struct llist_head list;</span><br><span style="color: hsl(120, 100%, 40%);">+       /* driver serving this UART */</span><br><span style="color: hsl(120, 100%, 40%);">+        const struct card_uart_driver *driver;</span><br><span style="color: hsl(120, 100%, 40%);">+        /* event-handler function */</span><br><span style="color: hsl(120, 100%, 40%);">+  void (*handle_event)(struct card_uart *cuart, enum card_uart_event evt, void *data);</span><br><span style="color: hsl(120, 100%, 40%);">+  /* opaque pointer for user */</span><br><span style="color: hsl(120, 100%, 40%);">+ void *priv;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* is the transmitter currently busy (true) or not (false)? */</span><br><span style="color: hsl(120, 100%, 40%);">+        bool tx_busy;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* is the receiver currently enabled or not? */</span><br><span style="color: hsl(120, 100%, 40%);">+       bool rx_enabled;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /*! after how many bytes should we notify the user? If this is '1', we will</span><br><span style="color: hsl(120, 100%, 40%);">+    *  issue CUART_E_RX_SINGLE; if it is > 1, we will issue CUART_E_RX_COMPLETE */</span><br><span style="color: hsl(120, 100%, 40%);">+    uint32_t rx_threshold;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* driver-specific private data */</span><br><span style="color: hsl(120, 100%, 40%);">+    union {</span><br><span style="color: hsl(120, 100%, 40%);">+               struct {</span><br><span style="color: hsl(120, 100%, 40%);">+                      /* ringbuffer on receive side */</span><br><span style="color: hsl(120, 100%, 40%);">+                      uint8_t rx_buf[256];</span><br><span style="color: hsl(120, 100%, 40%);">+                  struct ringbuffer rx_ringbuf;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                       /* pointer to (user-allocated) transmit buffer and length */</span><br><span style="color: hsl(120, 100%, 40%);">+                  const uint8_t *tx_buf;</span><br><span style="color: hsl(120, 100%, 40%);">+                        size_t tx_buf_len;</span><br><span style="color: hsl(120, 100%, 40%);">+                    /* index: offset of next to be transmitted byte in tx_buf */</span><br><span style="color: hsl(120, 100%, 40%);">+                  size_t tx_index;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                    struct osmo_fd ofd;</span><br><span style="color: hsl(120, 100%, 40%);">+                   unsigned int baudrate;</span><br><span style="color: hsl(120, 100%, 40%);">+                } tty;</span><br><span style="color: hsl(120, 100%, 40%);">+        } u;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Open the Card UART */</span><br><span style="color: hsl(120, 100%, 40%);">+int card_uart_open(struct card_uart *cuart, const char *driver_name, const char *device_name);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Close the Card UART */</span><br><span style="color: hsl(120, 100%, 40%);">+int card_uart_close(struct card_uart *cuart);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Schedule (asynchronous) transmit data via UART; optionally enable Rx after completion */</span><br><span style="color: hsl(120, 100%, 40%);">+int card_uart_tx(struct card_uart *cuart, const uint8_t *data, size_t len, bool rx_after_complete);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Schedule (asynchronous) receive data via UART (after CUART_E_RX_COMPLETE) */</span><br><span style="color: hsl(120, 100%, 40%);">+int card_uart_rx(struct card_uart *cuart, uint8_t *data, size_t len);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int card_uart_ctrl(struct card_uart *cuart, enum card_uart_ctl ctl, bool enable);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Set the Rx notification threshold in number of bytes received */</span><br><span style="color: hsl(120, 100%, 40%);">+void card_uart_set_rx_threshold(struct card_uart *cuart, size_t rx_threshold);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void card_uart_notification(struct card_uart *cuart, enum card_uart_event evt, void *data);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int card_uart_driver_register(struct card_uart_driver *drv);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>diff --git a/ccid/cuart_driver_tty.c b/ccid/cuart_driver_tty.c</span><br><span>new file mode 100644</span><br><span>index 0000000..6bd2b52</span><br><span>--- /dev/null</span><br><span>+++ b/ccid/cuart_driver_tty.c</span><br><span>@@ -0,0 +1,287 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* Card (ICC) UART driver for simple serial readers attached to tty.</span><br><span style="color: hsl(120, 100%, 40%);">+ * This allows you to use the CCID core in Linux userspace against a serial reader */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <unistd.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <termios.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/ioctl.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/select.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/serial.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "cuart.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "utils_ringbuffer.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/***********************************************************************</span><br><span style="color: hsl(120, 100%, 40%);">+ * low-level helper routines</span><br><span style="color: hsl(120, 100%, 40%);">+ ***********************************************************************/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int _init_uart(int fd)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct termios tio;</span><br><span style="color: hsl(120, 100%, 40%);">+   int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     rc = tcgetattr(fd, &tio);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              perror("tcgetattr()");</span><br><span style="color: hsl(120, 100%, 40%);">+              return -EIO;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   tio.c_iflag = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+      tio.c_oflag = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+      tio.c_lflag = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+      tio.c_cflag = CREAD | CLOCAL | CSTOPB | PARENB | CS8 | B9600;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       rc = tcsetattr(fd, TCSANOW, &tio);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              perror("tcsetattr()");</span><br><span style="color: hsl(120, 100%, 40%);">+              return -EIO;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void _set_dtr(int fd, bool dtr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     int status, rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     rc = ioctl(fd, TIOCMGET, &status);</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(rc == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (dtr) /* set DTR */</span><br><span style="color: hsl(120, 100%, 40%);">+                status |= TIOCM_DTR;</span><br><span style="color: hsl(120, 100%, 40%);">+  else</span><br><span style="color: hsl(120, 100%, 40%);">+          status &= ~TIOCM_DTR;</span><br><span style="color: hsl(120, 100%, 40%);">+     rc = ioctl(fd, TIOCMSET, &status);</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(rc == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void _set_rts(int fd, bool rts)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int status, rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     rc = ioctl(fd, TIOCMGET, &status);</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(rc == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rts) /* set RTS */</span><br><span style="color: hsl(120, 100%, 40%);">+                status |= TIOCM_RTS;</span><br><span style="color: hsl(120, 100%, 40%);">+  else</span><br><span style="color: hsl(120, 100%, 40%);">+          status &= ~TIOCM_RTS;</span><br><span style="color: hsl(120, 100%, 40%);">+     rc = ioctl(fd, TIOCMSET, &status);</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(rc == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int read_timeout(int fd, uint8_t *out, size_t len, unsigned long timeout_ms)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct timeval tv = { .tv_sec = timeout_ms / 1000, .tv_usec = (timeout_ms % 1000) * 1000 };</span><br><span style="color: hsl(120, 100%, 40%);">+   fd_set rd_set;</span><br><span style="color: hsl(120, 100%, 40%);">+        int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     FD_ZERO(&rd_set);</span><br><span style="color: hsl(120, 100%, 40%);">+ FD_SET(fd, &rd_set);</span><br><span style="color: hsl(120, 100%, 40%);">+      rc = select(fd+1, &rd_set, NULL, NULL, &tv);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (rc == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+          return -ETIMEDOUT;</span><br><span style="color: hsl(120, 100%, 40%);">+    else if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+           return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return read(fd, out, len);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int _flush(int fd)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+#if 0</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t buf[1];</span><br><span style="color: hsl(120, 100%, 40%);">+       int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     while (1) {</span><br><span style="color: hsl(120, 100%, 40%);">+           rc = read_timeout(fd, buf, sizeof(buf), 10);</span><br><span style="color: hsl(120, 100%, 40%);">+          if (rc == -ETIMEDOUT)</span><br><span style="color: hsl(120, 100%, 40%);">+                 return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+             else if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                   return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+#else</span><br><span style="color: hsl(120, 100%, 40%);">+      return tcflush(fd, TCIFLUSH);</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/***********************************************************************</span><br><span style="color: hsl(120, 100%, 40%);">+ * Interface with card_uart (cuart) core</span><br><span style="color: hsl(120, 100%, 40%);">+ ***********************************************************************/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* forward-declaration */</span><br><span style="color: hsl(120, 100%, 40%);">+static struct card_uart_driver tty_uart_driver;</span><br><span style="color: hsl(120, 100%, 40%);">+static int tty_uart_close(struct card_uart *cuart);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int tty_uart_fd_cb(struct osmo_fd *ofd, unsigned int what)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct card_uart *cuart = (struct card_uart *) ofd->data;</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t buf[256];</span><br><span style="color: hsl(120, 100%, 40%);">+     int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (what & OSMO_FD_READ) {</span><br><span style="color: hsl(120, 100%, 40%);">+                int i;</span><br><span style="color: hsl(120, 100%, 40%);">+                /* read any pending bytes and feed them into ring buffer */</span><br><span style="color: hsl(120, 100%, 40%);">+           rc = read(ofd->fd, buf, sizeof(buf));</span><br><span style="color: hsl(120, 100%, 40%);">+              OSMO_ASSERT(rc > 0);</span><br><span style="color: hsl(120, 100%, 40%);">+               for (i = 0; i < rc; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 /* work-around for https://bugzilla.kernel.org/show_bug.cgi?id=205033 */</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (!cuart->rx_enabled)</span><br><span style="color: hsl(120, 100%, 40%);">+                            continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (cuart->rx_threshold == 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+                            /* bypass ringbuffer and report byte directly */</span><br><span style="color: hsl(120, 100%, 40%);">+                              card_uart_notification(cuart, CUART_E_RX_SINGLE, &buf[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+                        } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                              /* go via ringbuffer and notify only after threshold */</span><br><span style="color: hsl(120, 100%, 40%);">+                               ringbuffer_put(&cuart->u.tty.rx_ringbuf, buf[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+                              if (ringbuffer_num(&cuart->u.tty.rx_ringbuf) >= cuart->rx_threshold)</span><br><span style="color: hsl(120, 100%, 40%);">+                                     card_uart_notification(cuart, CUART_E_RX_COMPLETE, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+                     }</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (what & OSMO_FD_WRITE) {</span><br><span style="color: hsl(120, 100%, 40%);">+               unsigned int to_tx;</span><br><span style="color: hsl(120, 100%, 40%);">+           OSMO_ASSERT(cuart->u.tty.tx_buf_len > cuart->u.tty.tx_index);</span><br><span style="color: hsl(120, 100%, 40%);">+                /* push as many pending transmit bytes as possible */</span><br><span style="color: hsl(120, 100%, 40%);">+         to_tx = cuart->u.tty.tx_buf_len - cuart->u.tty.tx_index;</span><br><span style="color: hsl(120, 100%, 40%);">+                rc = write(ofd->fd, cuart->u.tty.tx_buf + cuart->u.tty.tx_index, to_tx);</span><br><span style="color: hsl(120, 100%, 40%);">+             OSMO_ASSERT(rc > 0);</span><br><span style="color: hsl(120, 100%, 40%);">+               cuart->u.tty.tx_index += rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             /* if no more bytes to transmit, disable OSMO_FD_WRITE */</span><br><span style="color: hsl(120, 100%, 40%);">+             if (cuart->u.tty.tx_index >= cuart->u.tty.tx_buf_len) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      ofd->when &= ~BSC_FD_WRITE;</span><br><span style="color: hsl(120, 100%, 40%);">+                    /* ensure everything is written (tx queue/fifo drained) */</span><br><span style="color: hsl(120, 100%, 40%);">+                    tcdrain(cuart->u.tty.ofd.fd);</span><br><span style="color: hsl(120, 100%, 40%);">+                      osmo_select_main(true);</span><br><span style="color: hsl(120, 100%, 40%);">+                       cuart->tx_busy = false;</span><br><span style="color: hsl(120, 100%, 40%);">+                    /* notify */</span><br><span style="color: hsl(120, 100%, 40%);">+                  card_uart_notification(cuart, CUART_E_TX_COMPLETE, (void *)cuart->u.tty.tx_buf);</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int tty_uart_open(struct card_uart *cuart, const char *device_name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     rc = ringbuffer_init(&cuart->u.tty.rx_ringbuf, cuart->u.tty.rx_buf, sizeof(cuart->u.tty.rx_buf));</span><br><span style="color: hsl(120, 100%, 40%);">+        if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  cuart->u.tty.ofd.fd = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+  rc = osmo_serial_init(device_name, B9600);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_fd_setup(&cuart->u.tty.ofd, rc, BSC_FD_READ, tty_uart_fd_cb, cuart, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+        cuart->u.tty.baudrate = B9600;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      rc = _init_uart(cuart->u.tty.ofd.fd);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              tty_uart_close(cuart);</span><br><span style="color: hsl(120, 100%, 40%);">+                return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   _flush(cuart->u.tty.ofd.fd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_fd_register(&cuart->u.tty.ofd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int tty_uart_close(struct card_uart *cuart)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_ASSERT(cuart->driver == &tty_uart_driver);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (cuart->u.tty.ofd.fd != -1) {</span><br><span style="color: hsl(120, 100%, 40%);">+           osmo_fd_unregister(&cuart->u.tty.ofd);</span><br><span style="color: hsl(120, 100%, 40%);">+         close(cuart->u.tty.ofd.fd);</span><br><span style="color: hsl(120, 100%, 40%);">+                cuart->u.tty.ofd.fd = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int tty_uart_async_tx(struct card_uart *cuart, const uint8_t *data, size_t len, bool rx_after)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(cuart->driver == &tty_uart_driver);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      cuart->u.tty.tx_buf = data;</span><br><span style="color: hsl(120, 100%, 40%);">+        cuart->u.tty.tx_buf_len = len;</span><br><span style="color: hsl(120, 100%, 40%);">+     cuart->u.tty.tx_buf_len = len;</span><br><span style="color: hsl(120, 100%, 40%);">+     cuart->tx_busy = true;</span><br><span style="color: hsl(120, 100%, 40%);">+     cuart->u.tty.ofd.when |= OSMO_FD_WRITE;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int tty_uart_async_rx(struct card_uart *cuart, uint8_t *data, size_t len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   int rc, i;</span><br><span style="color: hsl(120, 100%, 40%);">+    OSMO_ASSERT(cuart->driver == &tty_uart_driver);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* FIXME: actually do this asynchronously */</span><br><span style="color: hsl(120, 100%, 40%);">+  for (i = 0; i < len; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                rc = ringbuffer_get(&cuart->u.tty.rx_ringbuf, &data[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+           if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                        return i;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return i;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int tty_uart_ctrl(struct card_uart *cuart, enum card_uart_ctl ctl, bool enable)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct termios tio;</span><br><span style="color: hsl(120, 100%, 40%);">+   int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     switch (ctl) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case CUART_CTL_RX:</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = tcgetattr(cuart->u.tty.ofd.fd, &tio);</span><br><span style="color: hsl(120, 100%, 40%);">+             if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      perror("tcgetattr()");</span><br><span style="color: hsl(120, 100%, 40%);">+                      return -EIO;</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span style="color: hsl(120, 100%, 40%);">+             /* We do our best here, but lots of [USB] serial drivers seem to ignore</span><br><span style="color: hsl(120, 100%, 40%);">+                * CREAD, see https://bugzilla.kernel.org/show_bug.cgi?id=205033 */</span><br><span style="color: hsl(120, 100%, 40%);">+           if (enable)</span><br><span style="color: hsl(120, 100%, 40%);">+                   tio.c_cflag |= CREAD;</span><br><span style="color: hsl(120, 100%, 40%);">+         else</span><br><span style="color: hsl(120, 100%, 40%);">+                  tio.c_cflag &= ~CREAD;</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = tcsetattr(cuart->u.tty.ofd.fd, TCSANOW, &tio);</span><br><span style="color: hsl(120, 100%, 40%);">+            if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      perror("tcsetattr()");</span><br><span style="color: hsl(120, 100%, 40%);">+                      return -EIO;</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CUART_CTL_RST:</span><br><span style="color: hsl(120, 100%, 40%);">+           _set_rts(cuart->u.tty.ofd.fd, enable);</span><br><span style="color: hsl(120, 100%, 40%);">+             if (enable)</span><br><span style="color: hsl(120, 100%, 40%);">+                   _flush(cuart->u.tty.ofd.fd);</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CUART_CTL_POWER:</span><br><span style="color: hsl(120, 100%, 40%);">+ case CUART_CTL_CLOCK:</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+              return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct card_uart_ops tty_uart_ops = {</span><br><span style="color: hsl(120, 100%, 40%);">+    .open = tty_uart_open,</span><br><span style="color: hsl(120, 100%, 40%);">+        .close = tty_uart_close,</span><br><span style="color: hsl(120, 100%, 40%);">+      .async_tx = tty_uart_async_tx,</span><br><span style="color: hsl(120, 100%, 40%);">+        .async_rx = tty_uart_async_rx,</span><br><span style="color: hsl(120, 100%, 40%);">+        .ctrl = tty_uart_ctrl,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct card_uart_driver tty_uart_driver = {</span><br><span style="color: hsl(120, 100%, 40%);">+      .name = "tty",</span><br><span style="color: hsl(120, 100%, 40%);">+      .ops = &tty_uart_ops,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static __attribute__((constructor)) void on_dso_load_cuart_tty(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      card_uart_driver_register(&tty_uart_driver);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/ccid/cuart_test.c b/ccid/cuart_test.c</span><br><span>new file mode 100644</span><br><span>index 0000000..aff9de7</span><br><span>--- /dev/null</span><br><span>+++ b/ccid/cuart_test.c</span><br><span>@@ -0,0 +1,76 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#include <unistd.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdio.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "cuart.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct card_uart g_cuart;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void handle_event(struct card_uart *cuart, enum card_uart_event evt, void *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       printf("Handle Event '%s'\n", get_value_string(card_uart_event_vals, evt));</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (evt) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case CUART_E_RX_SINGLE:</span><br><span style="color: hsl(120, 100%, 40%);">+               printf("\t%02x\n", *(uint8_t *)data);</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int get_atr(uint8_t *atr, size_t max_len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       int i = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  card_uart_ctrl(&g_cuart, CUART_CTL_RST, true);</span><br><span style="color: hsl(120, 100%, 40%);">+    usleep(100000);</span><br><span style="color: hsl(120, 100%, 40%);">+       card_uart_ctrl(&g_cuart, CUART_CTL_RST, false);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ sleep(1);</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_select_main(true);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     for (i = 0; i < max_len; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = card_uart_rx(&g_cuart, &atr[i], 1);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (rc <= 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                       break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return i;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void test_apdu(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        const uint8_t select_mf[] = "\xa0\xa4\x04\x00\x02\x3f\x00";</span><br><span style="color: hsl(120, 100%, 40%);">+ card_uart_tx(&g_cuart, select_mf, 5, true);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_select_main(true);</span><br><span style="color: hsl(120, 100%, 40%);">+       /* we should get an RX_SINGLE event here */</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int main(int argc, char **argv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        uint8_t atr[64];</span><br><span style="color: hsl(120, 100%, 40%);">+      int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     g_cuart.handle_event = &handle_event;</span><br><span style="color: hsl(120, 100%, 40%);">+     rc = card_uart_open(&g_cuart, "tty", "/dev/ttyUSB5");</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              perror("opening UART");</span><br><span style="color: hsl(120, 100%, 40%);">+             exit(1);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   rc = get_atr(atr, sizeof(atr));</span><br><span style="color: hsl(120, 100%, 40%);">+       if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              perror("getting ATR");</span><br><span style="color: hsl(120, 100%, 40%);">+              exit(1);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+     printf("ATR: %s\n", osmo_hexdump(atr, rc));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       test_apdu();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        exit(0);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/ccid/utils_ringbuffer.c b/ccid/utils_ringbuffer.c</span><br><span>new file mode 100644</span><br><span>index 0000000..49c273c</span><br><span>--- /dev/null</span><br><span>+++ b/ccid/utils_ringbuffer.c</span><br><span>@@ -0,0 +1,109 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/**</span><br><span style="color: hsl(120, 100%, 40%);">+ * \file</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Ringbuffer functionality implementation.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (c) 2014-2018 Microchip Technology Inc. and its subsidiaries.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \asf_license_start</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \page License</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Subject to your compliance with these terms, you may use Microchip</span><br><span style="color: hsl(120, 100%, 40%);">+ * software and any derivatives exclusively with Microchip products.</span><br><span style="color: hsl(120, 100%, 40%);">+ * It is your responsibility to comply with third party license terms applicable</span><br><span style="color: hsl(120, 100%, 40%);">+ * to your use of third party software (including open source software) that</span><br><span style="color: hsl(120, 100%, 40%);">+ * may accompany Microchip software.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,</span><br><span style="color: hsl(120, 100%, 40%);">+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,</span><br><span style="color: hsl(120, 100%, 40%);">+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,</span><br><span style="color: hsl(120, 100%, 40%);">+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE</span><br><span style="color: hsl(120, 100%, 40%);">+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL</span><br><span style="color: hsl(120, 100%, 40%);">+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE</span><br><span style="color: hsl(120, 100%, 40%);">+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE</span><br><span style="color: hsl(120, 100%, 40%);">+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE.  TO THE FULLEST EXTENT</span><br><span style="color: hsl(120, 100%, 40%);">+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY</span><br><span style="color: hsl(120, 100%, 40%);">+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,</span><br><span style="color: hsl(120, 100%, 40%);">+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \asf_license_stop</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include "utils_ringbuffer.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/**</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Ringbuffer init</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int32_t ringbuffer_init(struct ringbuffer *const rb, void *buf, uint32_t size)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       /*</span><br><span style="color: hsl(120, 100%, 40%);">+     * buf size must be aligned to power of 2</span><br><span style="color: hsl(120, 100%, 40%);">+      */</span><br><span style="color: hsl(120, 100%, 40%);">+   if ((size & (size - 1)) != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+           return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* size - 1 is faster in calculation */</span><br><span style="color: hsl(120, 100%, 40%);">+       rb->size        = size - 1;</span><br><span style="color: hsl(120, 100%, 40%);">+        rb->read_index  = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+       rb->write_index = rb->read_index;</span><br><span style="color: hsl(120, 100%, 40%);">+       rb->buf         = (uint8_t *)buf;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/**</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Get one byte from ringbuffer</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int32_t ringbuffer_get(struct ringbuffer *const rb, uint8_t *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rb->write_index != rb->read_index) {</span><br><span style="color: hsl(120, 100%, 40%);">+                *data = rb->buf[rb->read_index & rb->size];</span><br><span style="color: hsl(120, 100%, 40%);">+              rb->read_index++;</span><br><span style="color: hsl(120, 100%, 40%);">+          return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return -ENOENT;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/**</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Put one byte to ringbuffer</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int32_t ringbuffer_put(struct ringbuffer *const rb, uint8_t data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        rb->buf[rb->write_index & rb->size] = data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /*</span><br><span style="color: hsl(120, 100%, 40%);">+     * buffer full strategy: new data will overwrite the oldest data in</span><br><span style="color: hsl(120, 100%, 40%);">+    * the buffer</span><br><span style="color: hsl(120, 100%, 40%);">+  */</span><br><span style="color: hsl(120, 100%, 40%);">+   if ((rb->write_index - rb->read_index) > rb->size) {</span><br><span style="color: hsl(120, 100%, 40%);">+              rb->read_index = rb->write_index - rb->size;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   rb->write_index++;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/**</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Return the element number of ringbuffer</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+uint32_t ringbuffer_num(const struct ringbuffer *const rb)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    return rb->write_index - rb->read_index;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/**</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Flush ringbuffer</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+uint32_t ringbuffer_flush(struct ringbuffer *const rb)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  rb->read_index = rb->write_index;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/ccid/utils_ringbuffer.h b/ccid/utils_ringbuffer.h</span><br><span>new file mode 100644</span><br><span>index 0000000..07043a6</span><br><span>--- /dev/null</span><br><span>+++ b/ccid/utils_ringbuffer.h</span><br><span>@@ -0,0 +1,115 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/**</span><br><span style="color: hsl(120, 100%, 40%);">+ * \file</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Ringbuffer declaration.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (c) 2014-2018 Microchip Technology Inc. and its subsidiaries.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \asf_license_start</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \page License</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Subject to your compliance with these terms, you may use Microchip</span><br><span style="color: hsl(120, 100%, 40%);">+ * software and any derivatives exclusively with Microchip products.</span><br><span style="color: hsl(120, 100%, 40%);">+ * It is your responsibility to comply with third party license terms applicable</span><br><span style="color: hsl(120, 100%, 40%);">+ * to your use of third party software (including open source software) that</span><br><span style="color: hsl(120, 100%, 40%);">+ * may accompany Microchip software.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,</span><br><span style="color: hsl(120, 100%, 40%);">+ * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,</span><br><span style="color: hsl(120, 100%, 40%);">+ * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,</span><br><span style="color: hsl(120, 100%, 40%);">+ * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE</span><br><span style="color: hsl(120, 100%, 40%);">+ * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL</span><br><span style="color: hsl(120, 100%, 40%);">+ * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE</span><br><span style="color: hsl(120, 100%, 40%);">+ * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE</span><br><span style="color: hsl(120, 100%, 40%);">+ * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE.  TO THE FULLEST EXTENT</span><br><span style="color: hsl(120, 100%, 40%);">+ * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY</span><br><span style="color: hsl(120, 100%, 40%);">+ * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,</span><br><span style="color: hsl(120, 100%, 40%);">+ * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \asf_license_stop</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+#ifndef _UTILS_RINGBUFFER_H_INCLUDED</span><br><span style="color: hsl(120, 100%, 40%);">+#define _UTILS_RINGBUFFER_H_INCLUDED</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef __cplusplus</span><br><span style="color: hsl(120, 100%, 40%);">+extern "C" {</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/**</span><br><span style="color: hsl(120, 100%, 40%);">+ * \addtogroup doc_driver_hal_utils_ringbuffer</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * @{</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/**</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Ring buffer element type</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ringbuffer {</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t *buf;         /** Buffer base address */</span><br><span style="color: hsl(120, 100%, 40%);">+      uint32_t size;        /** Buffer size */</span><br><span style="color: hsl(120, 100%, 40%);">+      uint32_t read_index;  /** Buffer read index */</span><br><span style="color: hsl(120, 100%, 40%);">+        uint32_t write_index; /** Buffer write index */</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/**</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Ring buffer init</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] rb The pointer to a ring buffer structure instance</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] buf Space to store the data</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] size The buffer length, must be aligned with power of 2</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return ERR_NONE on success, or an error code on failure.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int32_t ringbuffer_init(struct ringbuffer *const rb, void *buf, uint32_t size);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/**</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Get one byte from ring buffer, the user needs to handle the concurrent</span><br><span style="color: hsl(120, 100%, 40%);">+ * access on buffer via put/get/flush</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] rb The pointer to a ring buffer structure instance</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] data One byte space to store the read data</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return ERR_NONE on success, or an error code on failure.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int32_t ringbuffer_get(struct ringbuffer *const rb, uint8_t *data);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/**</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Put one byte to ring buffer, the user needs to handle the concurrent access</span><br><span style="color: hsl(120, 100%, 40%);">+ * on buffer via put/get/flush</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] rb The pointer to a ring buffer structure instance</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] data One byte data to be put into ring buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return ERR_NONE on success, or an error code on failure.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int32_t ringbuffer_put(struct ringbuffer *const rb, uint8_t data);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/**</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Return the element number of ring buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] rb The pointer to a ring buffer structure instance</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return The number of elements in ring buffer [0, rb->size]</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+uint32_t ringbuffer_num(const struct ringbuffer *const rb);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/**</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Flush ring buffer, the user needs to handle the concurrent access on buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ * via put/get/flush</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] rb The pointer to a ring buffer structure instance</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return ERR_NONE on success, or an error code on failure.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+uint32_t ringbuffer_flush(struct ringbuffer *const rb);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/**@}*/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef __cplusplus</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+#endif /* _UTILS_RINGBUFFER_H_INCLUDED */</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-ccid-firmware/+/15691">change 15691</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/osmo-ccid-firmware/+/15691"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-ccid-firmware </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Ic7e324d99f78b3bfb98fc667d9a1b7fa363f092d </div>
<div style="display:none"> Gerrit-Change-Number: 15691 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>