host_communication/card_emu: adapt to nwe req_ctx / queuing paradignm
diff --git a/firmware/src_simtrace/card_emu.c b/firmware/src_simtrace/card_emu.c
index 5c57ddf..fa028a1 100644
--- a/firmware/src_simtrace/card_emu.c
+++ b/firmware/src_simtrace/card_emu.c
@@ -30,6 +30,7 @@
 #include "card_emu.h"
 #include "req_ctx.h"
 #include "cardemu_prot.h"
+#include "linuxlist.h"
 
 
 #define NUM_SLOTS		2
@@ -135,6 +136,9 @@
 	struct req_ctx *uart_rx_ctx;	/* UART RX -> USB TX */
 	struct req_ctx *uart_tx_ctx;	/* USB RX -> UART TX */
 
+	struct llist_head usb_tx_queue;
+	struct llist_head uart_tx_queue;
+
 	struct {
 		uint32_t tx_bytes;
 		uint32_t rx_bytes;
@@ -142,6 +146,16 @@
 	} stats;
 };
 
+struct llist_head *card_emu_get_usb_tx_queue(struct card_handle *ch)
+{
+	return &ch->usb_tx_queue;
+}
+
+struct llist_head *card_emu_get_uart_tx_queue(struct card_handle *ch)
+{
+	return &ch->uart_tx_queue;
+}
+
 static void set_tpdu_state(struct card_handle *ch, enum tpdu_state new_ts);
 static void set_pts_state(struct card_handle *ch, enum pts_state new_ptss);
 
@@ -154,12 +168,14 @@
 	if (!rctx)
 		return;
 
-	rd = (struct cardemu_usb_msg_rx_data *) ch->uart_rx_ctx->data;
+	ch->uart_rx_ctx = NULL;
 
 	/* store length of data payload fild in header */
+	rd = (struct cardemu_usb_msg_rx_data *) ch->uart_rx_ctx->data;
 	rd->hdr.data_len = rctx->idx;
+
+	llist_add_tail(&rctx->list, &ch->usb_tx_queue);
 	req_ctx_set_state(rctx, RCTX_S_USB_TX_PENDING);
-	ch->uart_rx_ctx = NULL;
 
 	/* FIXME: call into USB code to see if this buffer can
 	 * be transmitted now */
@@ -214,6 +230,7 @@
 	ptsi->hdr.data_len = serialize_pts(ptsi->req, ch->pts.req);
 	serialize_pts(ptsi->resp, ch->pts.resp);
 
+	llist_add_tail(&rctx->list, &ch->usb_tx_queue);
 	req_ctx_set_state(rctx, RCTX_S_USB_TX_PENDING);
 
 	/* FIXME: call into USB code to see if this buffer can
@@ -637,11 +654,15 @@
 	/* ensure we are aware of any data that might be pending for
 	 * transmit */
 	if (!ch->uart_tx_ctx) {
-		ch->uart_tx_ctx = req_ctx_find_get(0, RCTX_S_UART_TX_PENDING,
-						   RCTX_S_UART_TX_BUSY);
-		if (!ch->uart_tx_ctx)
+		if (llist_empty(&ch->uart_tx_queue))
 			return 0;
 
+		/* dequeue first at head */
+		ch->uart_tx_ctx = llist_entry(ch->uart_tx_queue.next,
+					      struct req_ctx, list);
+		llist_del(&ch->uart_tx_ctx->list);
+		req_ctx_set_state(ch->uart_tx_ctx, RCTX_S_UART_TX_BUSY);
+
 		/* start with index zero */
 		ch->uart_tx_ctx->idx = 0;
 
@@ -855,6 +876,9 @@
 
 	memset(ch, 0, sizeof(*ch));
 
+	INIT_LLIST_HEAD(&ch->usb_tx_queue);
+	INIT_LLIST_HEAD(&ch->uart_tx_queue);
+
 	/* initialize the card_handle with reasonabe defaults */
 	ch->state = ISO_S_WAIT_POWER;
 	ch->vcc_active = 0;
diff --git a/firmware/src_simtrace/card_emu.h b/firmware/src_simtrace/card_emu.h
index 225c307..eea3478 100644
--- a/firmware/src_simtrace/card_emu.h
+++ b/firmware/src_simtrace/card_emu.h
@@ -24,6 +24,8 @@
 /* User sets a new ATR to be returned during next card reset */
 int card_emu_set_atr(struct card_handle *ch, const uint8_t *atr, uint8_t len);
 
+struct llist_head *card_emu_get_uart_tx_queue(struct card_handle *ch);
+struct llist_head *card_emu_get_usb_tx_queue(struct card_handle *ch);
 
 #define ENABLE_TX	0x01
 #define ENABLE_RX	0x02
diff --git a/firmware/src_simtrace/host_communication.c b/firmware/src_simtrace/host_communication.c
index 10561c4..6834c4a 100644
--- a/firmware/src_simtrace/host_communication.c
+++ b/firmware/src_simtrace/host_communication.c
@@ -1,5 +1,8 @@
 #include "board.h"
 #include "req_ctx.h"
+#include "linuxlist.h"
+
+static volatile uint32_t usbep_in_progress[BOARD_USB_NUMENDPOINTS];
 
 /* call-back after (successful?) transfer of a buffer */
 static void usb_write_cb(uint8_t *arg, uint8_t status, uint32_t transferred,
@@ -7,6 +10,8 @@
 {
 	struct req_ctx *rctx = (struct req_ctx *) arg;
 
+	usbep_in_progress[rctx->ep] = 0;
+
 	if (status != USBD_STATUS_SUCCESS)
 		TRACE_ERROR("%s error, status=%d\n", __func__, status);
 
@@ -14,15 +19,24 @@
 	req_ctx_set_state(rctx, RCTX_S_FREE);
 }
 
-int usb_to_host(void)
+int usb_refill_to_host(struct llist_head *queue, uint32_t ep)
 {
 	struct req_ctx *rctx;
 	int rc;
 
-	rctx = req_ctx_find_get(0, RCTX_S_USB_TX_PENDING, RCTX_S_USB_TX_BUSY);
+	if (usbep_in_progress[ep])
+		return 0;
 
-	/* FIXME: obtain endpoint number from req_ctx! */
-	rc = USBD_Write(PHONE_DATAIN, rctx->data, rctx->tot_len,
+	if (llist_empty(queue))
+		return 0;
+
+	rctx = llist_entry(queue->next, struct req_ctx, list);
+	llist_del(&rctx->list);
+
+	req_ctx_set_state(rctx, RCTX_S_USB_TX_BUSY);
+	rctx->ep = ep;
+
+	rc = USBD_Write(ep, rctx->data, rctx->tot_len,
 			(TransferCallback) &usb_write_cb, rctx);
 	if (rc != USBD_STATUS_SUCCESS) {
 		TRACE_ERROR("%s error %x\n", __func__, rc);
@@ -30,6 +44,8 @@
 		return 0;
 	}
 
+	usbep_in_progress[ep] = 1;
+
 	return 1;
 }
 
@@ -37,6 +53,9 @@
 			uint32_t remaining)
 {
 	struct req_ctx *rctx = (struct req_ctx *) arg;
+	struct llist_head *queue = (struct llist_head *) usbep_in_progress[rctx->ep];
+
+	usbep_in_progress[rctx->ep] = 0;
 
 	if (status != USBD_STATUS_SUCCESS) {
 		TRACE_ERROR("%s error, status=%d\n", __func__, status);
@@ -45,14 +64,19 @@
 		return;
 	}
 	req_ctx_set_state(rctx, RCTX_S_UART_TX_PENDING);
+	llist_add_tail(&rctx->list, queue);
 }
 
-int usb_from_host(int ep)
+int usb_refill_from_host(struct llist_head *queue, int ep)
 {
 	struct req_ctx *rctx;
 	int rc;
 
+	if (usbep_in_progress[ep])
+		return 0;
+
 	rctx = req_ctx_find_get(0, RCTX_S_FREE, RCTX_S_USB_RX_BUSY);
+	rctx->ep = ep;
 
 	rc = USBD_Read(ep, rctx->data, rctx->size,
 			(TransferCallback) &usb_read_cb, rctx);
@@ -60,7 +84,10 @@
 	if (rc != USBD_STATUS_SUCCESS) {
 		TRACE_ERROR("%s error %x\n", __func__, rc);
 		req_ctx_put(rctx);
+		return 0;
 	}
 
-	return 0;
+	usbep_in_progress[ep] = (uint32_t) queue;
+
+	return 1;
 }
diff --git a/firmware/src_simtrace/main.c b/firmware/src_simtrace/main.c
index 36d86ee..95adb7e 100644
--- a/firmware/src_simtrace/main.c
+++ b/firmware/src_simtrace/main.c
@@ -140,7 +140,6 @@
             last_simtrace_config = simtrace_config;
         } else {
             config_func_ptrs[simtrace_config].run();
-	    usb_to_host();
         }
     }
 }
diff --git a/firmware/src_simtrace/mode_cardemu.c b/firmware/src_simtrace/mode_cardemu.c
index 21f3735..f1bbaf7 100644
--- a/firmware/src_simtrace/mode_cardemu.c
+++ b/firmware/src_simtrace/mode_cardemu.c
@@ -1,6 +1,7 @@
 #include "board.h"
 #include "card_emu.h"
 #include "iso7816_fidi.h"
+#include "utils.h"
 
 #define TRACE_ENTRY()	TRACE_DEBUG("%s entering\n", __func__)
 
@@ -204,10 +205,8 @@
 /* main loop function, called repeatedly */
 void mode_cardemu_run(void)
 {
-
-	/* usb_to_host() is handled by main() */
-
 	if (ch1) {
+		/* drain the ring buffer from UART into card_emu */
 		while (1) {
 			__disable_irq();
 			if (rbuf_is_empty(&ch1_rb)) {
@@ -218,8 +217,9 @@
 			__enable_irq();
 			card_emu_process_rx_byte(ch1, byte);
 		}
+		usb_refill_to_host(card_emu_get_usb_tx_queue(ch1), PHONE_DATAIN);
+		usb_refill_from_host(card_emu_get_uart_tx_queue(ch1), PHONE_DATAOUT);
 	}
-	usb_from_host(PHONE_DATAOUT);
 
 #ifdef CARDEMU_SECOND_UART
 	if (ch2) {
diff --git a/firmware/src_simtrace/simtrace.h b/firmware/src_simtrace/simtrace.h
index 687d219..c116346 100644
--- a/firmware/src_simtrace/simtrace.h
+++ b/firmware/src_simtrace/simtrace.h
@@ -92,7 +92,8 @@
 void Timer_Init( void );
 void TC0_Counter_Reset( void );
 
-int usb_to_host(void);
-int usb_from_host(int ep);
+struct llist_head;
+int usb_refill_to_host(struct llist_head *queue, uint32_t ep);
+int usb_refill_from_host(struct llist_head *queue, int ep);
 
 #endif  /*  SIMTRACE_H  */