cuart: Integrate software WT (waiting time) timer

Change-Id: If94d7bdca0e5571d4f2f53862fc574c33a05ce43
diff --git a/ccid_common/cuart.c b/ccid_common/cuart.c
index fc3cfb6..4ea82ba 100644
--- a/ccid_common/cuart.c
+++ b/ccid_common/cuart.c
@@ -2,6 +2,7 @@
 #include <string.h>
 #include <osmocom/core/linuxlist.h>
 #include <osmocom/core/utils.h>
+#include <osmocom/core/timer.h>
 
 #include "cuart.h"
 
@@ -25,6 +26,34 @@
 	return NULL;
 }
 
+/* obtain the current ETU in us */
+static int get_etu_in_us(struct card_uart *cuart)
+{
+	/* FIXME: actually implement this based on the real baud rate */
+	return (1000000/9600);
+}
+
+/* software waiting-time timer has expired */
+static void card_uart_wtime_cb(void *data)
+{
+	struct card_uart *cuart = (struct card_uart *) data;
+	card_uart_notification(cuart, CUART_E_RX_TIMEOUT, NULL);
+	/* should we automatically disable the receiver? */
+}
+
+void card_uart_wtime_restart(struct card_uart *cuart)
+{
+	int secs, usecs;
+
+	usecs = get_etu_in_us(cuart) * cuart->wtime_etu;
+	if (usecs > 1000000) {
+		secs = usecs / 1000000;
+		usecs = usecs % 1000000;
+	} else
+		secs = 0;
+	osmo_timer_schedule(&cuart->wtime_tmr, secs, usecs);
+}
+
 int card_uart_open(struct card_uart *cuart, const char *driver_name, const char *device_name)
 {
 	struct card_uart_driver *drv = cuart_drv_by_name(driver_name);
@@ -33,8 +62,10 @@
 	if (!drv)
 		return -ENODEV;
 
+	cuart->wtime_etu = 9600; /* ISO 7816-3 Section 8.1 */
 	cuart->rx_enabled = true;
 	cuart->rx_threshold = 1;
+	osmo_timer_setup(&cuart->wtime_tmr, card_uart_wtime_cb, cuart);
 
 	rc = drv->ops->open(cuart, device_name);
 	if (rc < 0)
@@ -60,13 +91,19 @@
 	OSMO_ASSERT(cuart->driver);
 	OSMO_ASSERT(cuart->driver->ops);
 	OSMO_ASSERT(cuart->driver->ops->ctrl);
+
 	rc = cuart->driver->ops->ctrl(cuart, ctl, arg);
 	if (rc < 0)
 		return rc;
 
 	switch (ctl) {
+	case CUART_CTL_WTIME:
+		cuart->wtime_etu = arg;
+		break;
 	case CUART_CTL_RX:
 		cuart->rx_enabled = arg ? true : false;
+		if (!cuart->rx_enabled)
+			osmo_timer_del(&cuart->wtime_tmr);
 		break;
 	default:
 		break;