diff --git a/firmware/src_simtrace/card_emu.c b/firmware/src_simtrace/card_emu.c index 5c57ddff..fa028a18 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 card_handle { 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 @@ struct card_handle { } 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 @@ static void flush_rx_buffer(struct card_handle *ch) 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 @@ static void flush_pts(struct card_handle *ch) 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 @@ static int tx_byte_tpdu(struct card_handle *ch) /* 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 @@ struct card_handle *card_emu_init(uint8_t slot_num, uint8_t tc_chan, uint8_t uar 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 225c3070..eea34780 100644 --- a/firmware/src_simtrace/card_emu.h +++ b/firmware/src_simtrace/card_emu.h @@ -24,6 +24,8 @@ void card_emu_io_statechg(struct card_handle *ch, enum card_io io, int active); /* 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 10561c41..6834c4a4 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 @@ static void usb_write_cb(uint8_t *arg, uint8_t status, uint32_t transferred, { 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 @@ static void usb_write_cb(uint8_t *arg, uint8_t status, uint32_t transferred, 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 @@ int usb_to_host(void) return 0; } + usbep_in_progress[ep] = 1; + return 1; } @@ -37,6 +53,9 @@ static void usb_read_cb(uint8_t *arg, uint8_t status, uint32_t transferred, 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 @@ static void usb_read_cb(uint8_t *arg, uint8_t status, uint32_t transferred, 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 @@ int usb_from_host(int ep) 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 36d86ee5..95adb7e7 100644 --- a/firmware/src_simtrace/main.c +++ b/firmware/src_simtrace/main.c @@ -140,7 +140,6 @@ extern int main( void ) 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 21f3735e..f1bbaf79 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 @@ void mode_cardemu_exit(void) /* 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 @@ void mode_cardemu_run(void) __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 687d219d..c1163462 100644 --- a/firmware/src_simtrace/simtrace.h +++ b/firmware/src_simtrace/simtrace.h @@ -92,7 +92,8 @@ extern void MITM_run( void ); 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 */