From c7a58ba755f9ae47c6b1dd1cde662bd54850c968 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 18 Apr 2019 17:59:19 +0200 Subject: [PATCH] WIP: Actual 'main' integration of CCID using msgb queues for USB transfers Change-Id: I9b7dbbc72dd566be19b217a57767f8404e1b02c4 --- sysmoOCTSIM/main.c | 193 +++++++++++++++++++++++++++++++++++++++- sysmoOCTSIM/usb_start.c | 1 + sysmoOCTSIM/usb_start.h | 1 + 3 files changed, 194 insertions(+), 1 deletion(-) diff --git a/sysmoOCTSIM/main.c b/sysmoOCTSIM/main.c index 3c189eb..00ac669 100644 --- a/sysmoOCTSIM/main.c +++ b/sysmoOCTSIM/main.c @@ -21,6 +21,9 @@ #include #include #include + +#include + #include #include @@ -76,6 +79,8 @@ static const double sercom_glck_freqs[] = {100E6 / CONF_GCLK_GEN_2_DIV, 100E6 / */ static const uint8_t SIM_peripheral_GCLK_ID[] = {SERCOM0_GCLK_ID_CORE, SERCOM1_GCLK_ID_CORE, SERCOM2_GCLK_ID_CORE, SERCOM3_GCLK_ID_CORE, SERCOM4_GCLK_ID_CORE, SERCOM5_GCLK_ID_CORE, SERCOM6_GCLK_ID_CORE, SERCOM7_GCLK_ID_CORE}; +static void ccid_app_init(void); + static void board_init() { int i; @@ -102,8 +107,192 @@ static void board_init() usart_async_register_callback(SIM_peripheral_descriptors[i], USART_ASYNC_TXC_CB, SIM_tx_cb); // to count the number of bytes transmitted since we are using it asynchronously usart_async_enable(SIM_peripheral_descriptors[i]); } + + ccid_app_init(); } +/*********************************************************************** + * CCID Driver integration + ***********************************************************************/ + +#include +#include +#include "linuxlist_atomic.h" +#include "ccid_df.h" + +struct usb_ep_q { + const char *name; + /* msgb queue of pending to-be-transmitted (IN/IRQ) or completed received (OUT) + * USB transfers */ + struct llist_head list; + /* currently ongoing/processed msgb (USB transmit or receive */ + struct msgb *in_progress; +}; + +struct ccid_state { + /* msgb queue of free msgs */ + struct llist_head free_q; + + /* msgb queue of pending to-be-transmitted (IN EP) */ + struct usb_ep_q in_ep; + /* msgb queue of pending to-be-transmitted (IRQ EP) */ + struct usb_ep_q irq_ep; + /* msgb queue of completed received (OUT EP) */ + struct usb_ep_q out_ep; +}; +static struct ccid_state g_ccid_s; + +static void ccid_out_read_compl(const uint8_t ep, enum usb_xfer_code code, uint32_t transferred); +static void ccid_in_write_compl(const uint8_t ep, enum usb_xfer_code code, uint32_t transferred); +static void ccid_irq_write_compl(const uint8_t ep, enum usb_xfer_code code, uint32_t transferred); + +static void usb_ep_q_init(struct usb_ep_q *ep_q, const char *name) +{ + ep_q->name = name; + INIT_LLIST_HEAD(&ep_q->list); + ep_q->in_progress = NULL; +} + +static void ccid_app_init(void) +{ + /* initialize data structures */ + INIT_LLIST_HEAD(&g_ccid_s.free_q); + usb_ep_q_init(&g_ccid_s.in_ep, "IN"); + usb_ep_q_init(&g_ccid_s.irq_ep, "IRQ"); + usb_ep_q_init(&g_ccid_s.out_ep, "OUT"); + + /* OUT endpoint read complete callback (irq context) */ + ccid_df_register_callback(CCID_DF_CB_READ_OUT, (FUNC_PTR)&ccid_out_read_compl); + /* IN endpoint write complete callback (irq context) */ + ccid_df_register_callback(CCID_DF_CB_WRITE_IN, (FUNC_PTR)&ccid_in_write_compl); + /* IRQ endpoint write complete callback (irq context) */ + ccid_df_register_callback(CCID_DF_CB_WRITE_IRQ, (FUNC_PTR)&ccid_irq_write_compl); +} + +/* irqsafe version of msgb_enqueue */ +struct msgb *msgb_dequeue_irqsafe(struct llist_head *q) +{ + struct msgb *msg; + CRITICAL_SECTION_ENTER() + msg = msgb_dequeue(q); + CRITICAL_SECTION_LEAVE() + return msg; +} + +/* submit the next pending (if any) message for the IN EP */ +static int submit_next_in(void) +{ + struct usb_ep_q *ep_q = &g_ccid_s.in_ep; + struct msgb *msg; + int rc; + + OSMO_ASSERT(!ep_q->in_progress); + msg = msgb_dequeue_irqsafe(&ep_q->list); + if (!msg) + return 0; + + ep_q->in_progress = msg; + rc = ccid_df_write_in(msgb_data(msg), msgb_length(msg)); + if (rc != ERR_NONE) { + printf("EP %s failed: %d\r\n", ep_q->name, rc); + return -1; + } + return 1; + +} + +/* submit the next pending (if any) message for the IRQ EP */ +static int submit_next_irq(void) +{ + struct usb_ep_q *ep_q = &g_ccid_s.irq_ep; + struct msgb *msg; + int rc; + + OSMO_ASSERT(!ep_q->in_progress); + msg = msgb_dequeue_irqsafe(&ep_q->list); + if (!msg) + return 0; + + ep_q->in_progress = msg; + rc = ccid_df_write_irq(msgb_data(msg), msgb_length(msg)); + /* may return HALTED/ERROR/DISABLED/BUSY/ERR_PARAM/ERR_FUNC/ERR_DENIED */ + if (rc != ERR_NONE) { + printf("EP %s failed: %d\r\n", ep_q->name, rc); + return -1; + } + return 1; +} + +static int submit_next_out(void) +{ + struct usb_ep_q *ep_q = &g_ccid_s.out_ep; + struct msgb *msg; + int rc; + + OSMO_ASSERT(!ep_q->in_progress); + msg = msgb_dequeue_irqsafe(&g_ccid_s.free_q); + if (!msg) + return -1; + ep_q->in_progress = msg; + + rc = ccid_df_read_out(msgb_data(msg), msgb_tailroom(msg)); + if (rc != ERR_NONE) { + /* re-add to the list of free msgb's */ + llist_add_tail_at(&g_ccid_s.free_q, &msg->list); + return 0; + } + return 1; +} + +/* OUT endpoint read complete callback (irq context) */ +static void ccid_out_read_compl(const uint8_t ep, enum usb_xfer_code code, uint32_t transferred) +{ + struct msgb *msg = g_ccid_s.out_ep.in_progress; + + /* add just-received msg to tail of endpoint queue */ + OSMO_ASSERT(msg); + /* update msgb with the amount of data received */ + msgb_put(msg, transferred); + /* append to list of pending-to-be-handed messages */ + llist_add_tail_at(&msg->list, &g_ccid_s.out_ep.list); + + /* submit another [free] msgb to receive the next transfer */ + submit_next_out(); +} + +/* IN endpoint write complete callback (irq context) */ +static void ccid_in_write_compl(const uint8_t ep, enum usb_xfer_code code, uint32_t transferred) +{ + struct msgb *msg = g_ccid_s.in_ep.in_progress; + + OSMO_ASSERT(msg); + /* return the message back to the queue of free message buffers */ + llist_add_tail_at(&msg->list, &g_ccid_s.free_q); + g_ccid_s.in_ep.in_progress = NULL; + + /* submit the next pending to-be-transmitted msgb (if any) */ + submit_next_in(); +} + +/* IRQ endpoint write complete callback (irq context) */ +static void ccid_irq_write_compl(const uint8_t ep, enum usb_xfer_code code, uint32_t transferred) +{ + struct msgb *msg = g_ccid_s.irq_ep.in_progress; + + OSMO_ASSERT(msg); + /* return the message back to the queue of free message buffers */ + llist_add_tail_at(&msg->list, &g_ccid_s.free_q); + g_ccid_s.irq_ep.in_progress = NULL; + + /* submit the next pending to-be-transmitted msgb (if any) */ + submit_next_irq(); +} + + +/*********************************************************************** + * Command Line interface + ***********************************************************************/ + static int validate_slotnr(int argc, char **argv, int idx) { int slotnr; @@ -711,6 +900,7 @@ extern void testmode_init(void); #include "talloc.h" #include void *g_tall_ctx; +void *g_msgb_ctx; DEFUN(_talloc_report, cmd_talloc_report, "talloc-report", "Generate a talloc report") { @@ -721,7 +911,6 @@ DEFUN(talloc_test, cmd_talloc_test, "talloc-test", "Test the talloc allocator") { for (int i = 0; i < 10; i++) talloc_named_const(g_tall_ctx, 10, "sibling"); - msgb_alloc_c(g_tall_ctx, 1024, "foo"); } DEFUN(v_talloc_free, cmd_talloc_free, "talloc-free", "Release all memory") @@ -800,6 +989,8 @@ int main(void) talloc_enable_null_tracking(); g_tall_ctx = talloc_named_const(NULL, 0, "global"); printf("g_tall_ctx=%p\r\n", g_tall_ctx); + g_msgb_ctx = talloc_pool(g_tall_ctx, 20480); + talloc_set_memlimit(g_msgb_ctx, 20480); command_print_prompt(); while (true) { // main loop diff --git a/sysmoOCTSIM/usb_start.c b/sysmoOCTSIM/usb_start.c index 83fac81..c6d9fe9 100644 --- a/sysmoOCTSIM/usb_start.c +++ b/sysmoOCTSIM/usb_start.c @@ -89,4 +89,5 @@ void usb_init(void) { cdc_device_acm_init(); + ccid_df_init(); } diff --git a/sysmoOCTSIM/usb_start.h b/sysmoOCTSIM/usb_start.h index daf30cc..a99d1ad 100644 --- a/sysmoOCTSIM/usb_start.h +++ b/sysmoOCTSIM/usb_start.h @@ -14,6 +14,7 @@ extern "C" { #include "cdcdf_acm.h" #include "cdcdf_acm_desc.h" +#include "ccid_df.h" void usb_start(void); void cdc_device_acm_init(void);