diff options
author | Harald Welte <laforge@osmocom.org> | 2020-01-11 17:15:26 +0100 |
---|---|---|
committer | Harald Welte <laforge@osmocom.org> | 2021-06-06 11:46:49 +0200 |
commit | d2bc858ddf0d404ce05a46cadbe86010647816ea (patch) | |
tree | de4c35bfe270bf59c40c9015d5c5e8e7641b5345 | |
parent | 29de264d6e974f229f418972053320bd7bb56f9f (diff) |
firmware: More common infrastructure for USB handling
Let's move low-level handling of endpoint queue refill from the
individual apps into common/shared code.
Now the main simply has to call usb_process() for every interface,
and inbound messages will be dispatched to call-back functions from
there.
Change-Id: Ic6f9c6c1ffdbb0c9c3b284371ecc83b17e3be746
-rw-r--r-- | firmware/apps/cardem/main.c | 1 | ||||
-rw-r--r-- | firmware/libcommon/include/usb_buf.h | 14 | ||||
-rw-r--r-- | firmware/libcommon/source/host_communication.c | 46 | ||||
-rw-r--r-- | firmware/libcommon/source/mode_cardemu.c | 83 | ||||
-rw-r--r-- | firmware/libcommon/source/sniffer.c | 28 |
5 files changed, 109 insertions, 63 deletions
diff --git a/firmware/apps/cardem/main.c b/firmware/apps/cardem/main.c index a30a211..d52bfd7 100644 --- a/firmware/apps/cardem/main.c +++ b/firmware/apps/cardem/main.c @@ -221,6 +221,7 @@ extern int main(void) } last_simtrace_config = simtrace_config; } else { + //FIXME: usb_proces() for every interface in this configuration? if (config_func_ptrs[simtrace_config].run) { config_func_ptrs[simtrace_config].run(); } diff --git a/firmware/libcommon/include/usb_buf.h b/firmware/libcommon/include/usb_buf.h index 3a4eda2..4c795a8 100644 --- a/firmware/libcommon/include/usb_buf.h +++ b/firmware/libcommon/include/usb_buf.h @@ -42,5 +42,15 @@ int usb_drain_queue(uint8_t ep); void usb_buf_init(void); struct usb_buffered_ep *usb_get_buf_ep(uint8_t ep); -int usb_refill_to_host(uint8_t ep); -int usb_refill_from_host(uint8_t ep); +struct usb_if { + uint8_t if_num; /* interface number */ + uint8_t ep_out; /* OUT endpoint (0 if none) */ + uint8_t ep_in; /* IN endpint (0 if none) */ + uint8_t ep_int; /* INT endpoint (0 if none) */ + void *data; /* opaque data, passed through */ + struct { + /* call-back to be called for inclming messages on OUT EP */ + void (*rx_out)(struct msgb *msg, const struct usb_if *usb_if); + } ops; +}; +void usb_process(const struct usb_if *usb_if); diff --git a/firmware/libcommon/source/host_communication.c b/firmware/libcommon/source/host_communication.c index 9a6e5b3..e367b37 100644 --- a/firmware/libcommon/source/host_communication.c +++ b/firmware/libcommon/source/host_communication.c @@ -57,7 +57,7 @@ static void usb_write_cb(uint8_t *arg, uint8_t status, uint32_t transferred, } /* check if the spcified IN endpoint is idle and submit the next buffer from queue */ -int usb_refill_to_host(uint8_t ep) +static int usb_refill_to_host(uint8_t ep) { struct usb_buffered_ep *bep = usb_get_buf_ep(ep); struct msgb *msg; @@ -130,7 +130,7 @@ static void usb_read_cb(uint8_t *arg, uint8_t status, uint32_t transferred, } /* refill the read queue for data received from host PC on OUT EP, if needed */ -int usb_refill_from_host(uint8_t ep) +static int usb_refill_from_host(uint8_t ep) { struct usb_buffered_ep *bep = usb_get_buf_ep(ep); struct msgb *msg; @@ -198,3 +198,45 @@ int usb_drain_queue(uint8_t ep) return ret; } + + + +/* iterate over the queue of incoming USB commands and dispatch/execute + * them */ +static void process_any_usb_commands(const struct usb_if *usb_if) +{ + struct llist_head *queue = usb_get_queue(usb_if->ep_out); + struct llist_head *lh; + struct msgb *msg; + int i; + + /* limit the number of iterations to 10, to ensure we don't get + * stuck here without returning to main loop processing */ + for (i = 0; i < 10; i++) { + /* de-queue the list head in an irq-safe way */ + lh = llist_head_dequeue_irqsafe(queue); + if (!lh) + break; + msg = llist_entry(lh, struct msgb, list); + usb_if->ops.rx_out(msg, usb_if); + } +} + +/* perform any action related to USB processing (IRQ/INT/OUT EP refill, handling OUT) */ +void usb_process(const struct usb_if *usb_if) +{ + /* first try to send any pending messages on IRQ */ + if (usb_if->ep_int) + usb_refill_to_host(usb_if->ep_int); + + /* then try to send any pending messages on IN */ + if (usb_if->ep_in) + usb_refill_to_host(usb_if->ep_in); + + /* ensure we can handle incoming USB messages from the + * host */ + if (usb_if->ep_out) { + usb_refill_from_host(usb_if->ep_out); + process_any_usb_commands(usb_if); + } +} diff --git a/firmware/libcommon/source/mode_cardemu.c b/firmware/libcommon/source/mode_cardemu.c index ef6b379..1374dfa 100644 --- a/firmware/libcommon/source/mode_cardemu.c +++ b/firmware/libcommon/source/mode_cardemu.c @@ -34,6 +34,8 @@ #define TRACE_ENTRY() TRACE_DEBUG("%s entering\r\n", __func__) +static void dispatch_received_usb_msg(struct msgb *msg, const struct usb_if *usb_if); + #ifdef PINS_CARDSIM static const Pin pins_cardsim[] = PINS_CARDSIM; #endif @@ -68,9 +70,7 @@ struct cardem_inst { bool half_time_notified; } wt; int usb_pending_old; - uint8_t ep_out; - uint8_t ep_in; - uint8_t ep_int; + struct usb_if usb_if; const Pin pin_insert; #ifdef DETECT_VCC_BY_ADC uint32_t vcc_uv; @@ -90,9 +90,16 @@ struct cardem_inst cardem_inst[] = { .id = ID_USART1, .state = USART_RCV }, - .ep_out = SIMTRACE_CARDEM_USB_EP_USIM1_DATAOUT, - .ep_in = SIMTRACE_CARDEM_USB_EP_USIM1_DATAIN, - .ep_int = SIMTRACE_CARDEM_USB_EP_USIM1_INT, + .usb_if = { + .if_num = 0, + .ep_out = SIMTRACE_CARDEM_USB_EP_USIM1_DATAOUT, + .ep_in = SIMTRACE_CARDEM_USB_EP_USIM1_DATAIN, + .ep_int = SIMTRACE_CARDEM_USB_EP_USIM1_INT, + .data = &cardem_inst[0], + .ops = { + .rx_out = dispatch_received_usb_msg, + }, + }, #ifdef PIN_SET_USIM1_PRES .pin_insert = PIN_SET_USIM1_PRES, #endif @@ -105,9 +112,16 @@ struct cardem_inst cardem_inst[] = { .id = ID_USART0, .state = USART_RCV }, - .ep_out = SIMTRACE_CARDEM_USB_EP_USIM2_DATAOUT, - .ep_in = SIMTRACE_CARDEM_USB_EP_USIM2_DATAIN, - .ep_int = SIMTRACE_CARDEM_USB_EP_USIM2_INT, + .usb_if = { + .if_num = 1, + .ep_out = SIMTRACE_CARDEM_USB_EP_USIM2_DATAOUT, + .ep_in = SIMTRACE_CARDEM_USB_EP_USIM2_DATAIN, + .ep_int = SIMTRACE_CARDEM_USB_EP_USIM2_INT, + .data = &cardem_inst[1], + .ops = { + .rx_out = dispatch_received_usb_msg, + }, + }, #ifdef PIN_SET_USIM2_PRES .pin_insert = PIN_SET_USIM2_PRES, #endif @@ -787,8 +801,9 @@ static void dispatch_usb_command_modem(struct msgb *msg, struct cardem_inst *ci) } /* handle a single USB command as received from the USB host */ -static void dispatch_usb_command(struct msgb *msg, struct cardem_inst *ci) +static void dispatch_usb_command(struct msgb *msg, const struct usb_if *usb_if) { + struct cardem_inst *ci = usb_if->data; struct simtrace_msg_hdr *sh = (struct simtrace_msg_hdr *) msg->l1h; if (msgb_length(msg) < sizeof(*sh)) { @@ -817,7 +832,8 @@ static void dispatch_usb_command(struct msgb *msg, struct cardem_inst *ci) } } -static void dispatch_received_msg(struct msgb *msg, struct cardem_inst *ci) +/* handle a single USB transfer as received from the USB host */ +static void dispatch_received_usb_msg(struct msgb *msg, const struct usb_if *usb_if) { struct msgb *segm; struct simtrace_msg_hdr *mh; @@ -828,7 +844,7 @@ static void dispatch_received_msg(struct msgb *msg, struct cardem_inst *ci) mh = (struct simtrace_msg_hdr *) msg->data; if (mh->msg_len == msgb_length(msg)) { /* fast path: only one message in buffer */ - dispatch_usb_command(msg, ci); + dispatch_usb_command(msg, usb_if); return; } @@ -837,23 +853,23 @@ static void dispatch_received_msg(struct msgb *msg, struct cardem_inst *ci) while (1) { mh = (struct simtrace_msg_hdr *) msg->data; - segm = usb_buf_alloc(ci->ep_out); + segm = usb_buf_alloc(usb_if->ep_out); if (!segm) { TRACE_ERROR("%u: ENOMEM during msg segmentation\r\n", - ci->num); + usb_if->if_num); break; } if (mh->msg_len > msgb_length(msg)) { TRACE_ERROR("%u: Unexpected large message (%u bytes)\r\n", - ci->num, mh->msg_len); + usb_if->if_num, mh->msg_len); usb_buf_free(segm); break; } else { uint8_t *cur = msgb_put(segm, mh->msg_len); segm->l1h = segm->head; memcpy(cur, mh, mh->msg_len); - dispatch_usb_command(segm, ci); + dispatch_usb_command(segm, usb_if); } /* pull this message */ msgb_pull(msg, mh->msg_len); @@ -865,35 +881,14 @@ static void dispatch_received_msg(struct msgb *msg, struct cardem_inst *ci) usb_buf_free(msg); } -/* iterate over the queue of incoming USB commands and dispatch/execute - * them */ -static void process_any_usb_commands(struct llist_head *main_q, - struct cardem_inst *ci) -{ - struct llist_head *lh; - struct msgb *msg; - int i; - - /* limit the number of iterations to 10, to ensure we don't get - * stuck here without returning to main loop processing */ - for (i = 0; i < 10; i++) { - /* de-queue the list head in an irq-safe way */ - lh = llist_head_dequeue_irqsafe(main_q); - if (!lh) - break; - msg = llist_entry(lh, struct msgb, list); - dispatch_received_msg(msg, ci); - } -} - /* main loop function, called repeatedly */ void mode_cardemu_run(void) { - struct llist_head *queue; unsigned int i; for (i = 0; i < ARRAY_SIZE(cardem_inst); i++) { struct cardem_inst *ci = &cardem_inst[i]; + struct usb_if *usb_if = &ci->usb_if; /* drain the ring buffer from UART into card_emu */ while (1) { @@ -910,16 +905,6 @@ void mode_cardemu_run(void) process_io_statechg(ci); - /* first try to send any pending messages on IRQ */ - usb_refill_to_host(ci->ep_int); - - /* then try to send any pending messages on IN */ - usb_refill_to_host(ci->ep_in); - - /* ensure we can handle incoming USB messages from the - * host */ - usb_refill_from_host(ci->ep_out); - queue = usb_get_queue(ci->ep_out); - process_any_usb_commands(queue, ci); + usb_process(&ci->usb_if); } } diff --git a/firmware/libcommon/source/sniffer.c b/firmware/libcommon/source/sniffer.c index 57e2daa..7917bd8 100644 --- a/firmware/libcommon/source/sniffer.c +++ b/firmware/libcommon/source/sniffer.c @@ -975,20 +975,28 @@ static void usb_send_change(uint32_t flags) usb_msg_upd_len_and_submit(usb_msg); } +/* handle incoming message from USB OUT EP */ +static void dispatch_usb_out(struct msgb *msg, const struct usb_if *usb_if) +{ + /* currently we don't need any incoming data */ + msgb_free(msg); +} + +static const struct usb_if sniffer_usb_if = { + .if_num = 0, + .ep_in = SIMTRACE_USB_EP_CARD_DATAIN, + .ep_int = SIMTRACE_USB_EP_CARD_INT, + .ep_out = SIMTRACE_USB_EP_CARD_DATAOUT, + .ops = { + .rx_out = dispatch_usb_out, + } +}; + /* Main (idle/busy) loop of this USB configuration */ void Sniffer_run(void) { /* Handle USB queue */ - /* first try to send any pending messages on INT */ - usb_refill_to_host(SIMTRACE_USB_EP_CARD_INT); - /* then try to send any pending messages on IN */ - usb_refill_to_host(SIMTRACE_USB_EP_CARD_DATAIN); - /* ensure we can handle incoming USB messages from the host */ - /* currently we don't need any incoming data - usb_refill_from_host(SIMTRACE_USB_EP_CARD_DATAOUT); - struct llist_head *queue = usb_get_queue(SIMTRACE_USB_EP_CARD_DATAOUT); - process_any_usb_commands(queue); - */ + usb_process(&sniffer_usb_if); /* WARNING: the signal data and flags are not synchronized. We have to hope * the processing is fast enough to not land in the wrong state while data |