aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@osmocom.org>2020-01-11 17:15:26 +0100
committerHarald Welte <laforge@osmocom.org>2021-06-06 11:46:49 +0200
commitd2bc858ddf0d404ce05a46cadbe86010647816ea (patch)
treede4c35bfe270bf59c40c9015d5c5e8e7641b5345
parent29de264d6e974f229f418972053320bd7bb56f9f (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.c1
-rw-r--r--firmware/libcommon/include/usb_buf.h14
-rw-r--r--firmware/libcommon/source/host_communication.c46
-rw-r--r--firmware/libcommon/source/mode_cardemu.c83
-rw-r--r--firmware/libcommon/source/sniffer.c28
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