mirror of
https://gitea.osmocom.org/sim-card/simtrace2.git
synced 2026-03-16 21:28:33 +03:00
migrate from req_ctx to msgb
We now generalize the USB communiction and abandon the 'req_ctx' structure inherited from openpcd. Instead we use the libosmocore 'msgb' structure to handle incoming and outgoing USB tranfers. We also use linuxlist-based msgb-queues for each endpoint.
This commit is contained in:
@@ -97,7 +97,7 @@ C_LIBCHIP = $(notdir $(wildcard $(AT91LIB)/libchip_sam3s/source/*.c) $(wildcard
|
|||||||
C_LIBUSB = USBDescriptors.c USBRequests.c USBD.c USBDCallbacks.c USBDDriver.c USBDDriverCallbacks.c
|
C_LIBUSB = USBDescriptors.c USBRequests.c USBD.c USBDCallbacks.c USBDDriver.c USBDDriverCallbacks.c
|
||||||
C_LIBUSB_RT = dfu.c dfu_runtime.c
|
C_LIBUSB_RT = dfu.c dfu_runtime.c
|
||||||
C_LIBUSB_DFU = dfu.c dfu_desc.c dfu_driver.c
|
C_LIBUSB_DFU = dfu.c dfu_desc.c dfu_driver.c
|
||||||
C_LIBCOMMON = string.c stdio.c fputs.c req_ctx.c ringbuffer.c
|
C_LIBCOMMON = string.c stdio.c fputs.c usb_buf.c ringbuffer.c pseudo_talloc.c host_communication.c
|
||||||
|
|
||||||
C_BOARD = $(notdir $(wildcard libboard/common/source/*.c))
|
C_BOARD = $(notdir $(wildcard libboard/common/source/*.c))
|
||||||
C_BOARD += $(notdir $(wildcard libboard/$(BOARD)/source/*.c))
|
C_BOARD += $(notdir $(wildcard libboard/$(BOARD)/source/*.c))
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
C_FILES += $(C_LIBUSB_RT)
|
C_FILES += $(C_LIBUSB_RT)
|
||||||
|
|
||||||
C_FILES += card_emu.c ccid.c host_communication.c iso7816_4.c iso7816_fidi.c mitm.c mode_cardemu.c simtrace_iso7816.c sniffer.c tc_etu.c usb.c
|
C_FILES += card_emu.c ccid.c iso7816_4.c iso7816_fidi.c mitm.c mode_cardemu.c simtrace_iso7816.c sniffer.c tc_etu.c usb.c
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
#include "board.h"
|
#include "board.h"
|
||||||
#include "simtrace.h"
|
#include "simtrace.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "req_ctx.h"
|
|
||||||
#include "osmocom/core/timer.h"
|
#include "osmocom/core/timer.h"
|
||||||
|
|
||||||
unsigned int g_unique_id[4];
|
unsigned int g_unique_id[4];
|
||||||
@@ -128,8 +127,6 @@ extern int main(void)
|
|||||||
WDT_Enable(WDT, WDT_MR_WDRSTEN | WDT_MR_WDDBGHLT | WDT_MR_WDIDLEHLT |
|
WDT_Enable(WDT, WDT_MR_WDRSTEN | WDT_MR_WDDBGHLT | WDT_MR_WDIDLEHLT |
|
||||||
(WDT_GetPeriod(500) << 16) | WDT_GetPeriod(500));
|
(WDT_GetPeriod(500) << 16) | WDT_GetPeriod(500));
|
||||||
|
|
||||||
req_ctx_init();
|
|
||||||
|
|
||||||
PIO_InitializeInterrupts(0);
|
PIO_InitializeInterrupts(0);
|
||||||
|
|
||||||
EEFC_ReadUniqueID(g_unique_id);
|
EEFC_ReadUniqueID(g_unique_id);
|
||||||
|
|||||||
@@ -190,8 +190,6 @@ extern int main(void)
|
|||||||
WDT_Enable(WDT, WDT_MR_WDRSTEN | WDT_MR_WDDBGHLT | WDT_MR_WDIDLEHLT |
|
WDT_Enable(WDT, WDT_MR_WDRSTEN | WDT_MR_WDDBGHLT | WDT_MR_WDIDLEHLT |
|
||||||
(WDT_GetPeriod(500) << 16) | WDT_GetPeriod(500));
|
(WDT_GetPeriod(500) << 16) | WDT_GetPeriod(500));
|
||||||
|
|
||||||
//req_ctx_init();
|
|
||||||
|
|
||||||
PIO_InitializeInterrupts(0);
|
PIO_InitializeInterrupts(0);
|
||||||
|
|
||||||
EEFC_ReadUniqueID(g_unique_id);
|
EEFC_ReadUniqueID(g_unique_id);
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
C_FILES += $(C_LIBUSB_RT)
|
C_FILES += $(C_LIBUSB_RT)
|
||||||
|
|
||||||
C_FILES += card_emu.c ccid.c host_communication.c iso7816_4.c iso7816_fidi.c mitm.c mode_cardemu.c simtrace_iso7816.c sniffer.c tc_etu.c usb.c
|
C_FILES += card_emu.c ccid.c iso7816_4.c iso7816_fidi.c mitm.c mode_cardemu.c simtrace_iso7816.c sniffer.c tc_etu.c usb.c
|
||||||
|
|||||||
@@ -4,12 +4,12 @@
|
|||||||
#include "board.h"
|
#include "board.h"
|
||||||
#include "simtrace.h"
|
#include "simtrace.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "req_ctx.h"
|
|
||||||
#include "wwan_led.h"
|
#include "wwan_led.h"
|
||||||
#include "wwan_perst.h"
|
#include "wwan_perst.h"
|
||||||
#include "boardver_adc.h"
|
#include "boardver_adc.h"
|
||||||
#include "card_pres.h"
|
#include "card_pres.h"
|
||||||
#include "osmocom/core/timer.h"
|
#include "osmocom/core/timer.h"
|
||||||
|
#include "usb_buf.h"
|
||||||
|
|
||||||
static const Pin pin_hubpwr_override = PIN_PRTPWR_OVERRIDE;
|
static const Pin pin_hubpwr_override = PIN_PRTPWR_OVERRIDE;
|
||||||
static const Pin pin_hub_rst = {PIO_PA13, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT};
|
static const Pin pin_hub_rst = {PIO_PA13, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT};
|
||||||
@@ -231,6 +231,8 @@ void board_exec_dbg_cmd(int ch)
|
|||||||
|
|
||||||
void board_main_top(void)
|
void board_main_top(void)
|
||||||
{
|
{
|
||||||
|
usb_buf_init();
|
||||||
|
|
||||||
wwan_led_init();
|
wwan_led_init();
|
||||||
wwan_perst_init();
|
wwan_perst_init();
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ enum card_io {
|
|||||||
CARD_IO_CLK,
|
CARD_IO_CLK,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct card_handle *card_emu_init(uint8_t slot_num, uint8_t tc_chan, uint8_t uart_chan);
|
struct card_handle *card_emu_init(uint8_t slot_num, uint8_t tc_chan, uint8_t uart_chan,
|
||||||
|
uint8_t in_ep, uint8_t irq_ep);
|
||||||
|
|
||||||
/* process a single byte received from the reader */
|
/* process a single byte received from the reader */
|
||||||
void card_emu_process_rx_byte(struct card_handle *ch, uint8_t byte);
|
void card_emu_process_rx_byte(struct card_handle *ch, uint8_t byte);
|
||||||
@@ -25,7 +26,6 @@ void card_emu_io_statechg(struct card_handle *ch, enum card_io io, int active);
|
|||||||
int card_emu_set_atr(struct card_handle *ch, const uint8_t *atr, uint8_t len);
|
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_uart_tx_queue(struct card_handle *ch);
|
||||||
struct llist_head *card_emu_get_usb_tx_queue(struct card_handle *ch);
|
|
||||||
void card_emu_have_new_uart_tx(struct card_handle *ch);
|
void card_emu_have_new_uart_tx(struct card_handle *ch);
|
||||||
void card_emu_report_status(struct card_handle *ch);
|
void card_emu_report_status(struct card_handle *ch);
|
||||||
|
|
||||||
|
|||||||
@@ -113,8 +113,4 @@ extern void mode_cardemu_usart1_irq(void);
|
|||||||
void Timer_Init( void );
|
void Timer_Init( void );
|
||||||
void TC0_Counter_Reset( void );
|
void TC0_Counter_Reset( void );
|
||||||
|
|
||||||
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 */
|
#endif /* SIMTRACE_H */
|
||||||
|
|||||||
25
firmware/libcommon/include/talloc.h
Normal file
25
firmware/libcommon/include/talloc.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
/* minimalistic emulation of core talloc API functions used by msgb.c */
|
||||||
|
|
||||||
|
#define __TALLOC_STRING_LINE1__(s) #s
|
||||||
|
#define __TALLOC_STRING_LINE2__(s) __TALLOC_STRING_LINE1__(s)
|
||||||
|
#define __TALLOC_STRING_LINE3__ __TALLOC_STRING_LINE2__(__LINE__)
|
||||||
|
#define __location__ __FILE__ ":" __TALLOC_STRING_LINE3__
|
||||||
|
|
||||||
|
#define talloc_zero(ctx, type) (type *)_talloc_zero(ctx, sizeof(type), #type)
|
||||||
|
#define talloc_zero_size(ctx, size) _talloc_zero(ctx, size, __location__)
|
||||||
|
void *_talloc_zero(const void *ctx, size_t size, const char *name);
|
||||||
|
|
||||||
|
#define talloc_free(ctx) _talloc_free(ctx, __location__)
|
||||||
|
int _talloc_free(void *ptr, const char *location);
|
||||||
|
|
||||||
|
/* Unsupported! */
|
||||||
|
#define talloc_size(ctx, size) talloc_named_const(ctx, size, __location__)
|
||||||
|
void *talloc_named_const(const void *context, size_t size, const char *name);
|
||||||
|
void talloc_set_name_const(const void *ptr, const char *name);
|
||||||
|
char *talloc_strdup(const void *t, const char *p);
|
||||||
|
void *talloc_pool(const void *context, size_t size);
|
||||||
28
firmware/libcommon/include/usb_buf.h
Normal file
28
firmware/libcommon/include/usb_buf.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "osmocom/core/linuxlist.h"
|
||||||
|
#include "osmocom/core/msgb.h"
|
||||||
|
|
||||||
|
/* buffered USB endpoint (with queue of msgb) */
|
||||||
|
struct usb_buffered_ep {
|
||||||
|
/* endpoint number */
|
||||||
|
uint8_t ep;
|
||||||
|
/* OUT endpoint (1) or IN/IRQ (0)? */
|
||||||
|
uint8_t out_from_host;
|
||||||
|
/* currently any transfer in progress? */
|
||||||
|
volatile uint32_t in_progress;
|
||||||
|
/* Tx queue (IN) / Rx queue (OUT) */
|
||||||
|
struct llist_head queue;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct msgb *usb_buf_alloc(uint8_t ep);
|
||||||
|
void usb_buf_free(struct msgb *msg);
|
||||||
|
int usb_buf_submit(struct msgb *msg);
|
||||||
|
struct llist_head *usb_get_queue(uint8_t ep);
|
||||||
|
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);
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/* ISO7816-3 state machine for the card side */
|
/* ISO7816-3 state machine for the card side */
|
||||||
/* (C) 2010-2015 by Harald Welte <hwelte@hmw-consulting.de>
|
/* (C) 2010-2017 by Harald Welte <hwelte@hmw-consulting.de>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -31,9 +31,10 @@
|
|||||||
#include "iso7816_fidi.h"
|
#include "iso7816_fidi.h"
|
||||||
#include "tc_etu.h"
|
#include "tc_etu.h"
|
||||||
#include "card_emu.h"
|
#include "card_emu.h"
|
||||||
#include "req_ctx.h"
|
|
||||||
#include "cardemu_prot.h"
|
#include "cardemu_prot.h"
|
||||||
|
#include "usb_buf.h"
|
||||||
#include "osmocom/core/linuxlist.h"
|
#include "osmocom/core/linuxlist.h"
|
||||||
|
#include "osmocom/core/msgb.h"
|
||||||
|
|
||||||
|
|
||||||
#define NUM_SLOTS 2
|
#define NUM_SLOTS 2
|
||||||
@@ -114,6 +115,9 @@ struct card_handle {
|
|||||||
uint8_t tc_chan; /* TC channel number */
|
uint8_t tc_chan; /* TC channel number */
|
||||||
uint8_t uart_chan; /* UART channel */
|
uint8_t uart_chan; /* UART channel */
|
||||||
|
|
||||||
|
uint8_t in_ep; /* USB IN EP */
|
||||||
|
uint8_t irq_ep; /* USB IN EP */
|
||||||
|
|
||||||
uint32_t waiting_time; /* in clocks */
|
uint32_t waiting_time; /* in clocks */
|
||||||
|
|
||||||
/* ATR state machine */
|
/* ATR state machine */
|
||||||
@@ -138,10 +142,9 @@ struct card_handle {
|
|||||||
uint8_t hdr[5]; /* CLA INS P1 P2 P3 */
|
uint8_t hdr[5]; /* CLA INS P1 P2 P3 */
|
||||||
} tpdu;
|
} tpdu;
|
||||||
|
|
||||||
struct req_ctx *uart_rx_ctx; /* UART RX -> USB TX */
|
struct msgb *uart_rx_msg; /* UART RX -> USB TX */
|
||||||
struct req_ctx *uart_tx_ctx; /* USB RX -> UART TX */
|
struct msgb *uart_tx_msg; /* USB RX -> UART TX */
|
||||||
|
|
||||||
struct llist_head usb_tx_queue;
|
|
||||||
struct llist_head uart_tx_queue;
|
struct llist_head uart_tx_queue;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
@@ -151,11 +154,6 @@ struct card_handle {
|
|||||||
} stats;
|
} 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)
|
struct llist_head *card_emu_get_uart_tx_queue(struct card_handle *ch)
|
||||||
{
|
{
|
||||||
return &ch->uart_tx_queue;
|
return &ch->uart_tx_queue;
|
||||||
@@ -166,24 +164,23 @@ static void set_pts_state(struct card_handle *ch, enum pts_state new_ptss);
|
|||||||
|
|
||||||
static void flush_rx_buffer(struct card_handle *ch)
|
static void flush_rx_buffer(struct card_handle *ch)
|
||||||
{
|
{
|
||||||
struct req_ctx *rctx;
|
struct msgb *msg;
|
||||||
struct cardemu_usb_msg_rx_data *rd;
|
struct cardemu_usb_msg_rx_data *rd;
|
||||||
|
uint32_t data_len;
|
||||||
|
|
||||||
rctx = ch->uart_rx_ctx;
|
msg = ch->uart_rx_msg;
|
||||||
if (!rctx)
|
if (!msg)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ch->uart_rx_ctx = NULL;
|
ch->uart_rx_msg = NULL;
|
||||||
|
|
||||||
/* store length of data payload fild in header */
|
/* store length of data payload fild in header */
|
||||||
rd = (struct cardemu_usb_msg_rx_data *) rctx->data;
|
rd = (struct cardemu_usb_msg_rx_data *) msg->l1h;
|
||||||
rd->data_len = rctx->idx;
|
msg->l2h = &rd->data;
|
||||||
rd->hdr.msg_len = sizeof(*rd) + rd->data_len;
|
rd->data_len = msgb_l2len(msg);
|
||||||
|
rd->hdr.msg_len = msgb_length(msg);
|
||||||
|
|
||||||
req_ctx_set_state(rctx, RCTX_S_USB_TX_PENDING);
|
usb_buf_submit(msg);
|
||||||
/* no need for irqsafe operation, as the usb_tx_queue is
|
|
||||||
* processed only by the main loop context */
|
|
||||||
llist_add_tail(&rctx->list, &ch->usb_tx_queue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* convert a non-contiguous PTS request/responsei into a contiguous
|
/* convert a non-contiguous PTS request/responsei into a contiguous
|
||||||
@@ -223,23 +220,22 @@ static uint8_t csum_pts(const uint8_t *in)
|
|||||||
|
|
||||||
static void flush_pts(struct card_handle *ch)
|
static void flush_pts(struct card_handle *ch)
|
||||||
{
|
{
|
||||||
struct req_ctx *rctx;
|
struct msgb *msg;
|
||||||
struct cardemu_usb_msg_pts_info *ptsi;
|
struct cardemu_usb_msg_pts_info *ptsi;
|
||||||
|
|
||||||
rctx = req_ctx_find_get(0, RCTX_S_FREE, RCTX_S_UART_RX_BUSY);
|
msg = usb_buf_alloc(ch->in_ep);
|
||||||
if (!rctx)
|
if (!msg)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ptsi = (struct cardemu_usb_msg_pts_info *) rctx->data;
|
msg->l1h = msgb_put(msg, sizeof(*ptsi));
|
||||||
|
msg->l2h = msg->l1h + sizeof(ptsi->hdr);
|
||||||
|
ptsi = (struct cardemu_usb_msg_pts_info *) msg->l1h;
|
||||||
ptsi->hdr.msg_type = CEMU_USB_MSGT_DO_PTS;
|
ptsi->hdr.msg_type = CEMU_USB_MSGT_DO_PTS;
|
||||||
ptsi->hdr.msg_len = sizeof(*ptsi);
|
ptsi->hdr.msg_len = sizeof(*ptsi);
|
||||||
ptsi->pts_len = serialize_pts(ptsi->req, ch->pts.req);
|
ptsi->pts_len = serialize_pts(ptsi->req, ch->pts.req);
|
||||||
serialize_pts(ptsi->resp, ch->pts.resp);
|
serialize_pts(ptsi->resp, ch->pts.resp);
|
||||||
|
|
||||||
req_ctx_set_state(rctx, RCTX_S_USB_TX_PENDING);
|
usb_buf_submit(msg);
|
||||||
/* no need for irqsafe operation, as the usb_tx_queue is
|
|
||||||
* processed only by the main loop context */
|
|
||||||
llist_add_tail(&rctx->list, &ch->usb_tx_queue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void emu_update_fidi(struct card_handle *ch)
|
static void emu_update_fidi(struct card_handle *ch)
|
||||||
@@ -502,37 +498,35 @@ static unsigned int t0_num_data_bytes(uint8_t p3, int reader_to_card)
|
|||||||
/* add a just-received TPDU byte (from reader) to USB buffer */
|
/* add a just-received TPDU byte (from reader) to USB buffer */
|
||||||
static void add_tpdu_byte(struct card_handle *ch, uint8_t byte)
|
static void add_tpdu_byte(struct card_handle *ch, uint8_t byte)
|
||||||
{
|
{
|
||||||
struct req_ctx *rctx;
|
struct msgb *msg;
|
||||||
struct cardemu_usb_msg_rx_data *rd;
|
struct cardemu_usb_msg_rx_data *rd;
|
||||||
unsigned int num_data_bytes = t0_num_data_bytes(ch->tpdu.hdr[_P3], 0);
|
unsigned int num_data_bytes = t0_num_data_bytes(ch->tpdu.hdr[_P3], 0);
|
||||||
|
|
||||||
/* ensure we have a buffer */
|
/* ensure we have a buffer */
|
||||||
if (!ch->uart_rx_ctx) {
|
if (!ch->uart_rx_msg) {
|
||||||
rctx = ch->uart_rx_ctx = req_ctx_find_get(0, RCTX_S_FREE, RCTX_S_UART_RX_BUSY);
|
msg = ch->uart_rx_msg = usb_buf_alloc(ch->in_ep);
|
||||||
if (!ch->uart_rx_ctx) {
|
if (!ch->uart_rx_msg) {
|
||||||
TRACE_ERROR("%u: Received UART byte but ENOMEM\r\n",
|
TRACE_ERROR("%u: Received UART byte but ENOMEM\r\n",
|
||||||
ch->num);
|
ch->num);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
rd = (struct cardemu_usb_msg_rx_data *) ch->uart_rx_ctx->data;
|
msg->l1h = msgb_put(msg, sizeof(*rd));
|
||||||
|
rd = (struct cardemu_usb_msg_rx_data *) msg->l1h;
|
||||||
|
msg->l2h = msg->l1h + sizeof(rd->hdr);
|
||||||
cardemu_hdr_set(&rd->hdr, CEMU_USB_MSGT_DO_RX_DATA);
|
cardemu_hdr_set(&rd->hdr, CEMU_USB_MSGT_DO_RX_DATA);
|
||||||
rctx->tot_len = sizeof(*rd);
|
|
||||||
rctx->idx = 0;
|
|
||||||
} else
|
} else
|
||||||
rctx = ch->uart_rx_ctx;
|
msg = ch->uart_rx_msg;
|
||||||
|
|
||||||
rd = (struct cardemu_usb_msg_rx_data *) rctx->data;
|
rd = (struct cardemu_usb_msg_rx_data *) msg->l1h;
|
||||||
|
msgb_put_u8(msg, byte);
|
||||||
rd->data[rctx->idx++] = byte;
|
|
||||||
rctx->tot_len++;
|
|
||||||
|
|
||||||
/* check if the buffer is full. If so, send it */
|
/* check if the buffer is full. If so, send it */
|
||||||
if (rctx->tot_len >= sizeof(*rd) + num_data_bytes) {
|
if (msgb_length(msg) >= sizeof(*rd) + num_data_bytes) {
|
||||||
rd->flags |= CEMU_DATA_F_FINAL;
|
rd->flags |= CEMU_DATA_F_FINAL;
|
||||||
flush_rx_buffer(ch);
|
flush_rx_buffer(ch);
|
||||||
/* We need to transmit the SW now, */
|
/* We need to transmit the SW now, */
|
||||||
set_tpdu_state(ch, TPDU_S_WAIT_TX);
|
set_tpdu_state(ch, TPDU_S_WAIT_TX);
|
||||||
} else if (rctx->tot_len >= rctx->size)
|
} else if (msgb_tailroom(msg) <= 0)
|
||||||
flush_rx_buffer(ch);
|
flush_rx_buffer(ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -590,8 +584,9 @@ static enum tpdu_state next_tpdu_state(struct card_handle *ch)
|
|||||||
|
|
||||||
static void send_tpdu_header(struct card_handle *ch)
|
static void send_tpdu_header(struct card_handle *ch)
|
||||||
{
|
{
|
||||||
struct req_ctx *rctx;
|
struct msgb *msg;
|
||||||
struct cardemu_usb_msg_rx_data *rd;
|
struct cardemu_usb_msg_rx_data *rd;
|
||||||
|
uint8_t *cur;
|
||||||
|
|
||||||
TRACE_INFO("%u: %s: %02x %02x %02x %02x %02x\r\n",
|
TRACE_INFO("%u: %s: %02x %02x %02x %02x %02x\r\n",
|
||||||
ch->num, __func__,
|
ch->num, __func__,
|
||||||
@@ -600,32 +595,32 @@ static void send_tpdu_header(struct card_handle *ch)
|
|||||||
ch->tpdu.hdr[4]);
|
ch->tpdu.hdr[4]);
|
||||||
|
|
||||||
/* if we already/still have a context, send it off */
|
/* if we already/still have a context, send it off */
|
||||||
if (ch->uart_rx_ctx) {
|
if (ch->uart_rx_msg) {
|
||||||
TRACE_DEBUG("%u: have old buffer\r\n", ch->num);
|
TRACE_DEBUG("%u: have old buffer\r\n", ch->num);
|
||||||
if (ch->uart_rx_ctx->idx) {
|
if (msgb_l2len(ch->uart_rx_msg)) {
|
||||||
TRACE_DEBUG("%u: flushing old buffer\r\n", ch->num);
|
TRACE_DEBUG("%u: flushing old buffer\r\n", ch->num);
|
||||||
flush_rx_buffer(ch);
|
flush_rx_buffer(ch);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
TRACE_DEBUG("%u: allocating new buffer\r\n", ch->num);
|
|
||||||
/* ensure we have a new buffer */
|
|
||||||
ch->uart_rx_ctx = req_ctx_find_get(0, RCTX_S_FREE, RCTX_S_UART_RX_BUSY);
|
|
||||||
if (!ch->uart_rx_ctx) {
|
|
||||||
TRACE_ERROR("%u: %s: ENOMEM\r\n", ch->num, __func__);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
rctx = ch->uart_rx_ctx;
|
TRACE_DEBUG("%u: allocating new buffer\r\n", ch->num);
|
||||||
rd = (struct cardemu_usb_msg_rx_data *) rctx->data;
|
/* ensure we have a new buffer */
|
||||||
|
ch->uart_rx_msg = usb_buf_alloc(ch->in_ep);
|
||||||
|
if (!ch->uart_rx_msg) {
|
||||||
|
TRACE_ERROR("%u: %s: ENOMEM\r\n", ch->num, __func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
msg = ch->uart_rx_msg;
|
||||||
|
msg->l1h = msgb_put(msg, sizeof(*rd));
|
||||||
|
rd = (struct cardemu_usb_msg_rx_data *) msg->l1h;
|
||||||
|
|
||||||
/* initializ header */
|
/* initialize header */
|
||||||
|
msg->l2h = msg->l1h + sizeof(rd->hdr);
|
||||||
cardemu_hdr_set(&rd->hdr, CEMU_USB_MSGT_DO_RX_DATA);
|
cardemu_hdr_set(&rd->hdr, CEMU_USB_MSGT_DO_RX_DATA);
|
||||||
rd->flags = CEMU_DATA_F_TPDU_HDR;
|
rd->flags = CEMU_DATA_F_TPDU_HDR;
|
||||||
rctx->tot_len = sizeof(*rd) + sizeof(ch->tpdu.hdr);
|
|
||||||
rctx->idx = sizeof(ch->tpdu.hdr);
|
|
||||||
|
|
||||||
/* copy TPDU header to data field */
|
/* copy TPDU header to data field */
|
||||||
memcpy(rd->data, ch->tpdu.hdr, sizeof(ch->tpdu.hdr));
|
cur = msgb_put(msg, sizeof(ch->tpdu.hdr));
|
||||||
|
memcpy(cur, ch->tpdu.hdr, sizeof(ch->tpdu.hdr));
|
||||||
/* rd->data_len is set in flush_rx_buffer() */
|
/* rd->data_len is set in flush_rx_buffer() */
|
||||||
|
|
||||||
flush_rx_buffer(ch);
|
flush_rx_buffer(ch);
|
||||||
@@ -674,33 +669,29 @@ process_byte_tpdu(struct card_handle *ch, uint8_t byte)
|
|||||||
/* tx a single byte to be transmitted to the reader */
|
/* tx a single byte to be transmitted to the reader */
|
||||||
static int tx_byte_tpdu(struct card_handle *ch)
|
static int tx_byte_tpdu(struct card_handle *ch)
|
||||||
{
|
{
|
||||||
struct req_ctx *rctx;
|
struct msgb *msg;
|
||||||
struct cardemu_usb_msg_tx_data *td;
|
struct cardemu_usb_msg_tx_data *td;
|
||||||
uint8_t byte;
|
uint8_t byte;
|
||||||
|
|
||||||
/* ensure we are aware of any data that might be pending for
|
/* ensure we are aware of any data that might be pending for
|
||||||
* transmit */
|
* transmit */
|
||||||
if (!ch->uart_tx_ctx) {
|
if (!ch->uart_tx_msg) {
|
||||||
/* uart_tx_queue is filled from main loop, so no need
|
/* uart_tx_queue is filled from main loop, so no need
|
||||||
* for irq-safe operations */
|
* for irq-safe operations */
|
||||||
if (llist_empty(&ch->uart_tx_queue))
|
if (llist_empty(&ch->uart_tx_queue))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* dequeue first at head */
|
/* dequeue first at head */
|
||||||
ch->uart_tx_ctx = llist_entry(ch->uart_tx_queue.next,
|
ch->uart_tx_msg = msgb_dequeue(&ch->uart_tx_queue);
|
||||||
struct req_ctx, list);
|
ch->uart_tx_msg->l1h = ch->uart_tx_msg->data;
|
||||||
llist_del(&ch->uart_tx_ctx->list);
|
msg = ch->uart_tx_msg;
|
||||||
req_ctx_set_state(ch->uart_tx_ctx, RCTX_S_UART_TX_BUSY);
|
msgb_pull(msg, sizeof(*td));
|
||||||
|
|
||||||
/* start with index zero */
|
|
||||||
ch->uart_tx_ctx->idx = 0;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
rctx = ch->uart_tx_ctx;
|
msg = ch->uart_tx_msg;
|
||||||
td = (struct cardemu_usb_msg_tx_data *) rctx->data;
|
td = (struct cardemu_usb_msg_tx_data *) msg->l1h;
|
||||||
|
|
||||||
/* take the next pending byte out of the rctx */
|
/* take the next pending byte out of the msgb */
|
||||||
byte = td->data[rctx->idx++];
|
byte = msgb_pull_u8(msg);
|
||||||
|
|
||||||
card_emu_uart_tx(ch->uart_chan, byte);
|
card_emu_uart_tx(ch->uart_chan, byte);
|
||||||
|
|
||||||
@@ -719,8 +710,7 @@ static int tx_byte_tpdu(struct card_handle *ch)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* check if the buffer has now been fully transmitted */
|
/* check if the buffer has now been fully transmitted */
|
||||||
if ((rctx->idx >= td->data_len) ||
|
if (msgb_length(msg) == 0) {
|
||||||
(td->data + rctx->idx >= rctx->data + rctx->tot_len)) {
|
|
||||||
if (td->flags & CEMU_DATA_F_PB_AND_RX) {
|
if (td->flags & CEMU_DATA_F_PB_AND_RX) {
|
||||||
/* we have just sent the procedure byte and now
|
/* we have just sent the procedure byte and now
|
||||||
* need to continue receiving */
|
* need to continue receiving */
|
||||||
@@ -733,8 +723,8 @@ static int tx_byte_tpdu(struct card_handle *ch)
|
|||||||
card_set_state(ch, ISO_S_WAIT_TPDU);
|
card_set_state(ch, ISO_S_WAIT_TPDU);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
req_ctx_set_state(rctx, RCTX_S_FREE);
|
usb_buf_free(msg);
|
||||||
ch->uart_tx_ctx = NULL;
|
ch->uart_tx_msg = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -836,15 +826,16 @@ void card_emu_have_new_uart_tx(struct card_handle *ch)
|
|||||||
|
|
||||||
void card_emu_report_status(struct card_handle *ch)
|
void card_emu_report_status(struct card_handle *ch)
|
||||||
{
|
{
|
||||||
struct req_ctx *rctx;
|
struct msgb *msg;
|
||||||
struct cardemu_usb_msg_status *sts;
|
struct cardemu_usb_msg_status *sts;
|
||||||
|
|
||||||
rctx = req_ctx_find_get(0, RCTX_S_FREE, RCTX_S_UART_RX_BUSY);
|
msg = usb_buf_alloc(ch->in_ep);
|
||||||
if (!rctx)
|
if (!msg)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
rctx->tot_len = sizeof(*sts);
|
msg->l1h = msgb_put(msg, sizeof(*sts));
|
||||||
sts = (struct cardemu_usb_msg_status *)rctx->data;
|
msg->l2h = msg->l1h + sizeof(sts->hdr);
|
||||||
|
sts = (struct cardemu_usb_msg_status *) msg->l1h;
|
||||||
sts->hdr.msg_type = CEMU_USB_MSGT_DO_STATUS;
|
sts->hdr.msg_type = CEMU_USB_MSGT_DO_STATUS;
|
||||||
sts->hdr.msg_len = sizeof(*sts);
|
sts->hdr.msg_len = sizeof(*sts);
|
||||||
sts->flags = 0;
|
sts->flags = 0;
|
||||||
@@ -860,8 +851,7 @@ void card_emu_report_status(struct card_handle *ch)
|
|||||||
sts->wi = ch->wi;
|
sts->wi = ch->wi;
|
||||||
sts->waiting_time = ch->waiting_time;
|
sts->waiting_time = ch->waiting_time;
|
||||||
|
|
||||||
llist_add_tail(&rctx->list, &ch->usb_tx_queue);
|
usb_buf_submit(msg);
|
||||||
req_ctx_set_state(rctx, RCTX_S_USB_TX_PENDING);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* hardware driver informs us that a card I/O signal has changed */
|
/* hardware driver informs us that a card I/O signal has changed */
|
||||||
@@ -957,7 +947,8 @@ static const uint8_t default_atr[] = { 0x3B, 0x02, 0x14, 0x50 };
|
|||||||
|
|
||||||
static struct card_handle card_handles[NUM_SLOTS];
|
static struct card_handle card_handles[NUM_SLOTS];
|
||||||
|
|
||||||
struct card_handle *card_emu_init(uint8_t slot_num, uint8_t tc_chan, uint8_t uart_chan)
|
struct card_handle *card_emu_init(uint8_t slot_num, uint8_t tc_chan, uint8_t uart_chan,
|
||||||
|
uint8_t in_ep, uint8_t irq_ep)
|
||||||
{
|
{
|
||||||
struct card_handle *ch;
|
struct card_handle *ch;
|
||||||
|
|
||||||
@@ -968,11 +959,12 @@ struct card_handle *card_emu_init(uint8_t slot_num, uint8_t tc_chan, uint8_t uar
|
|||||||
|
|
||||||
memset(ch, 0, sizeof(*ch));
|
memset(ch, 0, sizeof(*ch));
|
||||||
|
|
||||||
INIT_LLIST_HEAD(&ch->usb_tx_queue);
|
|
||||||
INIT_LLIST_HEAD(&ch->uart_tx_queue);
|
INIT_LLIST_HEAD(&ch->uart_tx_queue);
|
||||||
|
|
||||||
/* initialize the card_handle with reasonabe defaults */
|
/* initialize the card_handle with reasonabe defaults */
|
||||||
ch->num = slot_num;
|
ch->num = slot_num;
|
||||||
|
ch->irq_ep = irq_ep;
|
||||||
|
ch->in_ep = in_ep;
|
||||||
ch->state = ISO_S_WAIT_POWER;
|
ch->state = ISO_S_WAIT_POWER;
|
||||||
ch->vcc_active = 0;
|
ch->vcc_active = 0;
|
||||||
ch->in_reset = 1;
|
ch->in_reset = 1;
|
||||||
|
|||||||
@@ -1,126 +1,168 @@
|
|||||||
//#define TRACE_LEVEL 6
|
#include "board.h"
|
||||||
|
#include "llist_irqsafe.h"
|
||||||
|
#include "usb_buf.h"
|
||||||
|
|
||||||
|
#include "osmocom/core/linuxlist.h"
|
||||||
|
#include "osmocom/core/msgb.h"
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#include "board.h"
|
/***********************************************************************
|
||||||
#include "req_ctx.h"
|
* USBD Integration API
|
||||||
#include "osmocom/core/linuxlist.h"
|
***********************************************************************/
|
||||||
#include "llist_irqsafe.h"
|
|
||||||
|
|
||||||
static volatile uint32_t usbep_in_progress[BOARD_USB_NUMENDPOINTS];
|
|
||||||
|
|
||||||
/* call-back after (successful?) transfer of a buffer */
|
/* call-back after (successful?) transfer of a buffer */
|
||||||
static void usb_write_cb(uint8_t *arg, uint8_t status, uint32_t transferred,
|
static void usb_write_cb(uint8_t *arg, uint8_t status, uint32_t transferred,
|
||||||
uint32_t remaining)
|
uint32_t remaining)
|
||||||
{
|
{
|
||||||
struct req_ctx *rctx = (struct req_ctx *) arg;
|
struct msgb *msg = (struct msgb *) arg;
|
||||||
|
struct usb_buffered_ep *bep = msg->dst;
|
||||||
|
|
||||||
TRACE_DEBUG("%s (EP=%u)\r\n", __func__, rctx->ep);
|
TRACE_DEBUG("%s (EP=0x%02x)\r\n", __func__, bep->ep);
|
||||||
|
|
||||||
__disable_irq();
|
__disable_irq();
|
||||||
usbep_in_progress[rctx->ep]--;
|
bep->in_progress--;
|
||||||
__enable_irq();
|
__enable_irq();
|
||||||
TRACE_DEBUG("%u: in_progress=%d\n", rctx->ep, usbep_in_progress[rctx->ep]);
|
TRACE_DEBUG("%u: in_progress=%d\n", bep->ep, bep->in_progress);
|
||||||
|
|
||||||
if (status != USBD_STATUS_SUCCESS)
|
if (status != USBD_STATUS_SUCCESS)
|
||||||
TRACE_ERROR("%s error, status=%d\n", __func__, status);
|
TRACE_ERROR("%s error, status=%d\n", __func__, status);
|
||||||
|
|
||||||
/* release request contxt to pool */
|
usb_buf_free(msg);
|
||||||
req_ctx_set_state(rctx, RCTX_S_FREE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int usb_refill_to_host(struct llist_head *queue, uint32_t ep)
|
int usb_refill_to_host(uint8_t ep)
|
||||||
{
|
{
|
||||||
struct req_ctx *rctx;
|
struct usb_buffered_ep *bep = usb_get_buf_ep(ep);
|
||||||
|
struct msgb *msg;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if (bep->out_from_host) {
|
||||||
|
TRACE_ERROR("EP 0x%02x is not IN\r\n", bep->ep);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
__disable_irq();
|
__disable_irq();
|
||||||
if (usbep_in_progress[ep]) {
|
if (bep->in_progress) {
|
||||||
__enable_irq();
|
__enable_irq();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (llist_empty(queue)) {
|
if (llist_empty(&bep->queue)) {
|
||||||
__enable_irq();
|
__enable_irq();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
usbep_in_progress[ep]++;
|
bep->in_progress++;
|
||||||
|
|
||||||
rctx = llist_entry(queue->next, struct req_ctx, list);
|
msg = msgb_dequeue(&bep->queue);
|
||||||
llist_del(&rctx->list);
|
|
||||||
|
|
||||||
__enable_irq();
|
__enable_irq();
|
||||||
|
|
||||||
TRACE_DEBUG("%u: in_progress=%d\n", ep, usbep_in_progress[ep]);
|
TRACE_DEBUG("%s (EP=0x%02x), in_progress=%d\r\n", __func__, ep, bep->in_progress);
|
||||||
TRACE_DEBUG("%s (EP=%u)\r\n", __func__, ep);
|
|
||||||
|
|
||||||
req_ctx_set_state(rctx, RCTX_S_USB_TX_BUSY);
|
msg->dst = bep;
|
||||||
rctx->ep = ep;
|
|
||||||
|
|
||||||
rc = USBD_Write(ep, rctx->data, rctx->tot_len,
|
rc = USBD_Write(ep, msgb_data(msg), msgb_length(msg),
|
||||||
(TransferCallback) &usb_write_cb, rctx);
|
(TransferCallback) &usb_write_cb, msg);
|
||||||
if (rc != USBD_STATUS_SUCCESS) {
|
if (rc != USBD_STATUS_SUCCESS) {
|
||||||
TRACE_ERROR("%s error %x\n", __func__, rc);
|
TRACE_ERROR("%s error %x\n", __func__, rc);
|
||||||
req_ctx_set_state(rctx, RCTX_S_USB_TX_PENDING);
|
/* re-insert to head of queue */
|
||||||
|
llist_add_irqsafe(&msg->list, &bep->queue);
|
||||||
__disable_irq();
|
__disable_irq();
|
||||||
usbep_in_progress[ep]--;
|
bep->in_progress--;
|
||||||
__enable_irq();
|
__enable_irq();
|
||||||
TRACE_DEBUG("%u: in_progress=%d\n", ep, usbep_in_progress[ep]);
|
TRACE_DEBUG("%02x: in_progress=%d\n", bep->ep, bep->in_progress);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* call-back after (successful?) transfer of a buffer */
|
||||||
static void usb_read_cb(uint8_t *arg, uint8_t status, uint32_t transferred,
|
static void usb_read_cb(uint8_t *arg, uint8_t status, uint32_t transferred,
|
||||||
uint32_t remaining)
|
uint32_t remaining)
|
||||||
{
|
{
|
||||||
struct req_ctx *rctx = (struct req_ctx *) arg;
|
struct msgb *msg = (struct msgb *) arg;
|
||||||
struct llist_head *queue = (struct llist_head *) usbep_in_progress[rctx->ep];
|
struct usb_buffered_ep *bep = msg->dst;
|
||||||
|
|
||||||
TRACE_DEBUG("%s (EP=%u, len=%u, q=%p)\r\n", __func__,
|
TRACE_DEBUG("%s (EP=%u, len=%u, q=%p)\r\n", __func__,
|
||||||
rctx->ep, transferred, queue);
|
bep->ep, transferred, &bep->queue);
|
||||||
|
|
||||||
usbep_in_progress[rctx->ep] = 0;
|
bep->in_progress = 0;
|
||||||
|
|
||||||
if (status != USBD_STATUS_SUCCESS) {
|
if (status != USBD_STATUS_SUCCESS) {
|
||||||
TRACE_ERROR("%s error, status=%d\n", __func__, status);
|
TRACE_ERROR("%s error, status=%d\n", __func__, status);
|
||||||
/* release request contxt to pool */
|
usb_buf_free(msg);
|
||||||
req_ctx_put(rctx);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
rctx->tot_len = transferred;
|
msgb_put(msg, transferred);
|
||||||
req_ctx_set_state(rctx, RCTX_S_MAIN_PROCESSING);
|
llist_add_tail_irqsafe(&msg->list, &bep->queue);
|
||||||
llist_add_tail_irqsafe(&rctx->list, queue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int usb_refill_from_host(struct llist_head *queue, int ep)
|
int usb_refill_from_host(uint8_t ep)
|
||||||
{
|
{
|
||||||
struct req_ctx *rctx;
|
struct usb_buffered_ep *bep = usb_get_buf_ep(ep);
|
||||||
|
struct msgb *msg;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (usbep_in_progress[ep])
|
#if 0
|
||||||
|
if (!bep->out_from_host) {
|
||||||
|
TRACE_ERROR("EP 0x%02x is not OUT\r\n", bep->ep);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (bep->in_progress)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
TRACE_DEBUG("%s (EP=%u)\r\n", __func__, ep);
|
TRACE_DEBUG("%s (EP=0x%02x)\r\n", __func__, bep->ep);
|
||||||
|
|
||||||
rctx = req_ctx_find_get(0, RCTX_S_FREE, RCTX_S_USB_RX_BUSY);
|
msg = usb_buf_alloc(bep->ep);
|
||||||
if (!rctx)
|
if (!msg)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
msg->dst = bep;
|
||||||
|
msg->l1h = msg->head;
|
||||||
|
|
||||||
rctx->ep = ep;
|
bep->in_progress = 1;
|
||||||
usbep_in_progress[ep] = (uint32_t) queue;
|
|
||||||
|
|
||||||
rc = USBD_Read(ep, rctx->data, rctx->size,
|
|
||||||
(TransferCallback) &usb_read_cb, rctx);
|
|
||||||
|
|
||||||
|
rc = USBD_Read(ep, msg->head, msgb_tailroom(msg),
|
||||||
|
(TransferCallback) &usb_read_cb, msg);
|
||||||
if (rc != USBD_STATUS_SUCCESS) {
|
if (rc != USBD_STATUS_SUCCESS) {
|
||||||
TRACE_ERROR("%s error %x\n", __func__, rc);
|
TRACE_ERROR("%s error %s\n", __func__, rc);
|
||||||
req_ctx_put(rctx);
|
usb_buf_free(msg);
|
||||||
usbep_in_progress[ep] = 0;
|
bep->in_progress = 0;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int usb_drain_queue(uint8_t ep)
|
||||||
|
{
|
||||||
|
struct usb_buffered_ep *bep = usb_get_buf_ep(ep);
|
||||||
|
struct msgb *msg;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
/* wait until no transfers are in progress anymore and block
|
||||||
|
* further interrupts */
|
||||||
|
while (1) {
|
||||||
|
__disable_irq();
|
||||||
|
if (!bep->in_progress) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
__enable_irq();
|
||||||
|
/* retry */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* free all queued msgbs */
|
||||||
|
while ((msg = msgb_dequeue(&bep->queue))) {
|
||||||
|
usb_buf_free(msg);
|
||||||
|
ret++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* re-enable interrupts and return number of free'd msgbs */
|
||||||
|
__enable_irq();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,8 +7,9 @@
|
|||||||
#include "iso7816_fidi.h"
|
#include "iso7816_fidi.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "osmocom/core/linuxlist.h"
|
#include "osmocom/core/linuxlist.h"
|
||||||
|
#include "osmocom/core/msgb.h"
|
||||||
#include "llist_irqsafe.h"
|
#include "llist_irqsafe.h"
|
||||||
#include "req_ctx.h"
|
#include "usb_buf.h"
|
||||||
#include "cardemu_prot.h"
|
#include "cardemu_prot.h"
|
||||||
|
|
||||||
#define TRACE_ENTRY() TRACE_DEBUG("%s entering\r\n", __func__)
|
#define TRACE_ENTRY() TRACE_DEBUG("%s entering\r\n", __func__)
|
||||||
@@ -43,7 +44,7 @@ struct cardem_inst {
|
|||||||
uint32_t vcc_uv_last;
|
uint32_t vcc_uv_last;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct cardem_inst cardem_inst[] = {
|
struct cardem_inst cardem_inst[] = {
|
||||||
{
|
{
|
||||||
.num = 0,
|
.num = 0,
|
||||||
.usart_info = {
|
.usart_info = {
|
||||||
@@ -395,7 +396,7 @@ void mode_cardemu_init(void)
|
|||||||
PIO_ConfigureIt(&pin_usim1_vcc, usim1_vcc_irqhandler);
|
PIO_ConfigureIt(&pin_usim1_vcc, usim1_vcc_irqhandler);
|
||||||
PIO_EnableIt(&pin_usim1_vcc);
|
PIO_EnableIt(&pin_usim1_vcc);
|
||||||
#endif /* DETECT_VCC_BY_ADC */
|
#endif /* DETECT_VCC_BY_ADC */
|
||||||
cardem_inst[0].ch = card_emu_init(0, 2, 0);
|
cardem_inst[0].ch = card_emu_init(0, 2, 0, PHONE_DATAIN, PHONE_INT);
|
||||||
|
|
||||||
#ifdef CARDEMU_SECOND_UART
|
#ifdef CARDEMU_SECOND_UART
|
||||||
INIT_LLIST_HEAD(&cardem_inst[1].usb_out_queue);
|
INIT_LLIST_HEAD(&cardem_inst[1].usb_out_queue);
|
||||||
@@ -409,7 +410,7 @@ void mode_cardemu_init(void)
|
|||||||
PIO_ConfigureIt(&pin_usim2_vcc, usim2_vcc_irqhandler);
|
PIO_ConfigureIt(&pin_usim2_vcc, usim2_vcc_irqhandler);
|
||||||
PIO_EnableIt(&pin_usim2_vcc);
|
PIO_EnableIt(&pin_usim2_vcc);
|
||||||
#endif /* DETECT_VCC_BY_ADC */
|
#endif /* DETECT_VCC_BY_ADC */
|
||||||
cardem_inst[1].ch = card_emu_init(1, 0, 1);
|
cardem_inst[1].ch = card_emu_init(1, 0, 1, CARDEM_USIM2_DATAIN, CARDEM_USIM2_INT);
|
||||||
#endif /* CARDEMU_SECOND_UART */
|
#endif /* CARDEMU_SECOND_UART */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -419,7 +420,7 @@ void mode_cardemu_exit(void)
|
|||||||
TRACE_ENTRY();
|
TRACE_ENTRY();
|
||||||
|
|
||||||
/* FIXME: stop tc_fdt */
|
/* FIXME: stop tc_fdt */
|
||||||
/* FIXME: release all rctx, unlink them from any queue */
|
/* FIXME: release all msg, unlink them from any queue */
|
||||||
|
|
||||||
PIO_DisableIt(&pin_usim1_rst);
|
PIO_DisableIt(&pin_usim1_rst);
|
||||||
PIO_DisableIt(&pin_usim1_vcc);
|
PIO_DisableIt(&pin_usim1_vcc);
|
||||||
@@ -439,25 +440,24 @@ void mode_cardemu_exit(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* handle a single USB command as received from the USB host */
|
/* handle a single USB command as received from the USB host */
|
||||||
static void dispatch_usb_command(struct req_ctx *rctx, struct cardem_inst *ci)
|
static void dispatch_usb_command(struct msgb *msg, struct cardem_inst *ci)
|
||||||
{
|
{
|
||||||
struct cardemu_usb_msg_hdr *hdr;
|
struct cardemu_usb_msg_hdr *hdr;
|
||||||
struct cardemu_usb_msg_set_atr *atr;
|
struct cardemu_usb_msg_set_atr *atr;
|
||||||
struct cardemu_usb_msg_cardinsert *cardins;
|
struct cardemu_usb_msg_cardinsert *cardins;
|
||||||
struct llist_head *queue;
|
struct llist_head *queue;
|
||||||
|
|
||||||
hdr = (struct cardemu_usb_msg_hdr *) rctx->data;
|
hdr = (struct cardemu_usb_msg_hdr *) msg->l1h;
|
||||||
switch (hdr->msg_type) {
|
switch (hdr->msg_type) {
|
||||||
case CEMU_USB_MSGT_DT_TX_DATA:
|
case CEMU_USB_MSGT_DT_TX_DATA:
|
||||||
queue = card_emu_get_uart_tx_queue(ci->ch);
|
queue = card_emu_get_uart_tx_queue(ci->ch);
|
||||||
req_ctx_set_state(rctx, RCTX_S_UART_TX_PENDING);
|
llist_add_tail(&msg->list, queue);
|
||||||
llist_add_tail(&rctx->list, queue);
|
|
||||||
card_emu_have_new_uart_tx(ci->ch);
|
card_emu_have_new_uart_tx(ci->ch);
|
||||||
break;
|
break;
|
||||||
case CEMU_USB_MSGT_DT_SET_ATR:
|
case CEMU_USB_MSGT_DT_SET_ATR:
|
||||||
atr = (struct cardemu_usb_msg_set_atr *) hdr;
|
atr = (struct cardemu_usb_msg_set_atr *) hdr;
|
||||||
card_emu_set_atr(ci->ch, atr->atr, atr->atr_len);
|
card_emu_set_atr(ci->ch, atr->atr, atr->atr_len);
|
||||||
req_ctx_put(rctx);
|
usb_buf_free(msg);
|
||||||
break;
|
break;
|
||||||
case CEMU_USB_MSGT_DT_CARDINSERT:
|
case CEMU_USB_MSGT_DT_CARDINSERT:
|
||||||
cardins = (struct cardemu_usb_msg_cardinsert *) hdr;
|
cardins = (struct cardemu_usb_msg_cardinsert *) hdr;
|
||||||
@@ -467,7 +467,7 @@ static void dispatch_usb_command(struct req_ctx *rctx, struct cardem_inst *ci)
|
|||||||
PIO_Set(&ci->pin_insert);
|
PIO_Set(&ci->pin_insert);
|
||||||
else
|
else
|
||||||
PIO_Clear(&ci->pin_insert);
|
PIO_Clear(&ci->pin_insert);
|
||||||
req_ctx_put(rctx);
|
usb_buf_free(msg);
|
||||||
break;
|
break;
|
||||||
case CEMU_USB_MSGT_DT_GET_STATUS:
|
case CEMU_USB_MSGT_DT_GET_STATUS:
|
||||||
card_emu_report_status(ci->ch);
|
card_emu_report_status(ci->ch);
|
||||||
@@ -475,48 +475,56 @@ static void dispatch_usb_command(struct req_ctx *rctx, struct cardem_inst *ci)
|
|||||||
case CEMU_USB_MSGT_DT_GET_STATS:
|
case CEMU_USB_MSGT_DT_GET_STATS:
|
||||||
default:
|
default:
|
||||||
/* FIXME */
|
/* FIXME */
|
||||||
req_ctx_put(rctx);
|
usb_buf_free(msg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dispatch_received_rctx(struct req_ctx *rctx, struct cardem_inst *ci)
|
static void dispatch_received_msg(struct msgb *msg, struct cardem_inst *ci)
|
||||||
{
|
{
|
||||||
struct req_ctx *segm;
|
struct msgb *segm;
|
||||||
struct cardemu_usb_msg_hdr *mh;
|
struct cardemu_usb_msg_hdr *mh;
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
/* check if we have multiple concatenated commands in
|
/* check if we have multiple concatenated commands in
|
||||||
* one message. USB endpoints are streams that don't
|
* one message. USB endpoints are streams that don't
|
||||||
* preserve the message boundaries */
|
* preserve the message boundaries */
|
||||||
mh = (struct cardemu_usb_msg_hdr *) rctx->data;
|
mh = (struct cardemu_usb_msg_hdr *) msg->data;
|
||||||
if (mh->msg_len == rctx->tot_len) {
|
if (mh->msg_len == msgb_length(msg)) {
|
||||||
/* fast path: only one message in buffer */
|
/* fast path: only one message in buffer */
|
||||||
dispatch_usb_command(rctx, ci);
|
dispatch_usb_command(msg, ci);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* slow path: iterate over list of messages, allocating one new
|
/* slow path: iterate over list of messages, allocating one new
|
||||||
* reqe_ctx per segment */
|
* reqe_ctx per segment */
|
||||||
for (mh = (struct cardemu_usb_msg_hdr *) rctx->data;
|
while (1) {
|
||||||
(uint8_t *)mh < rctx->data + rctx->tot_len;
|
mh = (struct cardemu_usb_msg_hdr *) msg->head;
|
||||||
mh = (struct cardemu_usb_msg_hdr * ) ((uint8_t *)mh + mh->msg_len)) {
|
|
||||||
segm = req_ctx_find_get(0, RCTX_S_FREE, RCTX_S_MAIN_PROCESSING);
|
segm = usb_buf_alloc(ci->ep_out);
|
||||||
if (!segm) {
|
if (!segm) {
|
||||||
TRACE_ERROR("%u: ENOMEM during rctx segmentation\r\n",
|
TRACE_ERROR("%u: ENOMEM during msg segmentation\r\n",
|
||||||
ci->num);
|
ci->num);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
segm->idx = 0;
|
|
||||||
segm->tot_len = mh->msg_len;
|
if (mh->msg_len > msgb_length(msg)) {
|
||||||
memcpy(segm->data, mh, segm->tot_len);
|
TRACE_ERROR("%u: Unexpected large message (%u bytes)\n",
|
||||||
dispatch_usb_command(segm, ci);
|
ci->num, mh->msg_len);
|
||||||
i++;
|
usb_buf_free(segm);
|
||||||
|
} 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);
|
||||||
|
}
|
||||||
|
/* pull this message */
|
||||||
|
msgb_pull(msg, mh->msg_len);
|
||||||
|
/* abort if we're done */
|
||||||
|
if (msgb_length(msg) <= 0)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* release the master req_ctx, as all segments have been
|
usb_buf_free(msg);
|
||||||
* processed now */
|
|
||||||
req_ctx_put(rctx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* iterate over the queue of incoming USB commands and dispatch/execute
|
/* iterate over the queue of incoming USB commands and dispatch/execute
|
||||||
@@ -525,7 +533,7 @@ static void process_any_usb_commands(struct llist_head *main_q,
|
|||||||
struct cardem_inst *ci)
|
struct cardem_inst *ci)
|
||||||
{
|
{
|
||||||
struct llist_head *lh;
|
struct llist_head *lh;
|
||||||
struct req_ctx *rctx;
|
struct msgb *msg;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* limit the number of iterations to 10, to ensure we don't get
|
/* limit the number of iterations to 10, to ensure we don't get
|
||||||
@@ -535,8 +543,8 @@ static void process_any_usb_commands(struct llist_head *main_q,
|
|||||||
lh = llist_head_dequeue_irqsafe(main_q);
|
lh = llist_head_dequeue_irqsafe(main_q);
|
||||||
if (!lh)
|
if (!lh)
|
||||||
break;
|
break;
|
||||||
rctx = llist_entry(lh, struct req_ctx, list);
|
msg = llist_entry(lh, struct msgb, list);
|
||||||
dispatch_received_rctx(rctx, ci);
|
dispatch_received_msg(msg, ci);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -562,19 +570,16 @@ void mode_cardemu_run(void)
|
|||||||
//TRACE_ERROR("%uRx%02x\r\n", i, byte);
|
//TRACE_ERROR("%uRx%02x\r\n", i, byte);
|
||||||
}
|
}
|
||||||
|
|
||||||
queue = card_emu_get_usb_tx_queue(ci->ch);
|
/* first try to send any pending messages on IRQ */
|
||||||
int usb_pending = llist_count(queue);
|
usb_refill_to_host(ci->ep_int);
|
||||||
if (usb_pending != ci->usb_pending_old) {
|
|
||||||
TRACE_DEBUG("%u usb_pending=%d\r\n",
|
/* then try to send any pending messages on IN */
|
||||||
i, usb_pending);
|
usb_refill_to_host(ci->ep_in);
|
||||||
ci->usb_pending_old = usb_pending;
|
|
||||||
}
|
|
||||||
usb_refill_to_host(queue, ci->ep_in);
|
|
||||||
|
|
||||||
/* ensure we can handle incoming USB messages from the
|
/* ensure we can handle incoming USB messages from the
|
||||||
* host */
|
* host */
|
||||||
queue = &ci->usb_out_queue;
|
usb_refill_from_host(ci->ep_out);
|
||||||
usb_refill_from_host(queue, ci->ep_out);
|
queue = usb_get_queue(ci->ep_out);
|
||||||
process_any_usb_commands(queue, ci);
|
process_any_usb_commands(queue, ci);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
69
firmware/libcommon/source/pseudo_talloc.c
Normal file
69
firmware/libcommon/source/pseudo_talloc.c
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "talloc.h"
|
||||||
|
#include "trace.h"
|
||||||
|
#include "osmocom/core/utils.h"
|
||||||
|
|
||||||
|
#define NUM_RCTX_SMALL 10
|
||||||
|
#define RCTX_SIZE_SMALL 348
|
||||||
|
|
||||||
|
static uint8_t msgb_data[NUM_RCTX_SMALL][RCTX_SIZE_SMALL] __attribute__((aligned(sizeof(long))));
|
||||||
|
static uint8_t msgb_inuse[NUM_RCTX_SMALL];
|
||||||
|
|
||||||
|
void *_talloc_zero(const void *ctx, size_t size, const char *name)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
if (size > RCTX_SIZE_SMALL) {
|
||||||
|
TRACE_ERROR("%s() request too large(%d > %d)\r\n", __func__, size, RCTX_SIZE_SMALL);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(msgb_inuse); i++) {
|
||||||
|
if (!msgb_inuse[i]) {
|
||||||
|
uint8_t *out = msgb_data[i];
|
||||||
|
msgb_inuse[i] = 1;
|
||||||
|
memset(out, 0, size);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TRACE_ERROR("%s() out of memory!\r\n", __func__);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _talloc_free(void *ptr, const char *location)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
for (i = 0; i < ARRAY_SIZE(msgb_inuse); i++) {
|
||||||
|
if (ptr == msgb_data[i]) {
|
||||||
|
if (!msgb_inuse[i]) {
|
||||||
|
TRACE_ERROR("%s: double_free by \r\n", __func__, location);
|
||||||
|
} else {
|
||||||
|
msgb_inuse[i] = 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE_ERROR("%s: invalid pointer %p from %s\r\n", __func__, ptr, location);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void talloc_set_name_const(const void *ptr, const char *name)
|
||||||
|
{
|
||||||
|
/* do nothing */
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
void *talloc_named_const(const void *context, size_t size, const char *name)
|
||||||
|
{
|
||||||
|
if (size)
|
||||||
|
TRACE_ERROR("%s: called with size!=0 from %s\r\n", __func__, name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *talloc_pool(const void *context, size_t size)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -1,140 +0,0 @@
|
|||||||
/* USB Request Context for OpenPCD / OpenPICC / SIMtrace
|
|
||||||
* (C) 2006-2016 by Harald Welte <hwelte@hmw-consulting.de>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include "chip.h"
|
|
||||||
#include "utils.h"
|
|
||||||
#include "trace.h"
|
|
||||||
#include "req_ctx.h"
|
|
||||||
|
|
||||||
#define NUM_RCTX_SMALL 10
|
|
||||||
#define NUM_RCTX_LARGE 0
|
|
||||||
|
|
||||||
#define NUM_REQ_CTX (NUM_RCTX_SMALL+NUM_RCTX_LARGE)
|
|
||||||
|
|
||||||
static uint8_t rctx_data[NUM_RCTX_SMALL][RCTX_SIZE_SMALL];
|
|
||||||
static uint8_t rctx_data_large[NUM_RCTX_LARGE][RCTX_SIZE_LARGE];
|
|
||||||
|
|
||||||
static struct req_ctx req_ctx[NUM_REQ_CTX];
|
|
||||||
|
|
||||||
struct req_ctx __ramfunc *
|
|
||||||
req_ctx_find_get(int large, uint32_t old_state, uint32_t new_state)
|
|
||||||
{
|
|
||||||
struct req_ctx *toReturn = NULL;
|
|
||||||
unsigned long flags;
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
if (old_state >= RCTX_STATE_COUNT || new_state >= RCTX_STATE_COUNT) {
|
|
||||||
TRACE_DEBUG("Invalid parameters for req_ctx_find_get\r\n");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
local_irq_save(flags);
|
|
||||||
for (i = 0; i < ARRAY_SIZE(req_ctx); i++) {
|
|
||||||
if (req_ctx[i].state == old_state) {
|
|
||||||
toReturn = &req_ctx[i];
|
|
||||||
toReturn->state = new_state;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
local_irq_restore(flags);
|
|
||||||
|
|
||||||
TRACE_DEBUG("%s(%u, %u, %u)=%p\r\n", __func__, large, old_state,
|
|
||||||
new_state, toReturn);
|
|
||||||
|
|
||||||
return toReturn;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t req_ctx_num(struct req_ctx *ctx)
|
|
||||||
{
|
|
||||||
return ctx - req_ctx;
|
|
||||||
}
|
|
||||||
|
|
||||||
void req_ctx_set_state(struct req_ctx *ctx, uint32_t new_state)
|
|
||||||
{
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
TRACE_DEBUG("%s(ctx=%p, new_state=%u)\r\n", __func__, ctx, new_state);
|
|
||||||
|
|
||||||
if (new_state >= RCTX_STATE_COUNT) {
|
|
||||||
TRACE_DEBUG("Invalid new_state for req_ctx_set_state\r\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
local_irq_save(flags);
|
|
||||||
ctx->state = new_state;
|
|
||||||
local_irq_restore(flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DEBUG_REQCTX
|
|
||||||
void req_print(int state) {
|
|
||||||
int count = 0;
|
|
||||||
struct req_ctx *ctx, *last = NULL;
|
|
||||||
DEBUGP("State [%02i] start <==> ", state);
|
|
||||||
ctx = req_ctx_queues[state];
|
|
||||||
while (ctx) {
|
|
||||||
if (last != ctx->prev)
|
|
||||||
DEBUGP("*INV_PREV* ");
|
|
||||||
DEBUGP("%08X => ", ctx);
|
|
||||||
last = ctx;
|
|
||||||
ctx = ctx->next;
|
|
||||||
count++;
|
|
||||||
if (count > NUM_REQ_CTX) {
|
|
||||||
DEBUGP("*WILD POINTER* => ");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TRACE_DEBUG("NULL");
|
|
||||||
if (!req_ctx_queues[state] && req_ctx_tails[state]) {
|
|
||||||
TRACE_DEBUG("NULL head, NON-NULL tail\r\n");
|
|
||||||
}
|
|
||||||
if (last != req_ctx_tails[state]) {
|
|
||||||
TRACE_DEBUG("Tail does not match last element\r\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void req_ctx_put(struct req_ctx *ctx)
|
|
||||||
{
|
|
||||||
return req_ctx_set_state(ctx, RCTX_S_FREE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void req_ctx_init(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < NUM_RCTX_SMALL; i++) {
|
|
||||||
req_ctx[i].size = RCTX_SIZE_SMALL;
|
|
||||||
req_ctx[i].tot_len = 0;
|
|
||||||
req_ctx[i].data = rctx_data[i];
|
|
||||||
req_ctx[i].state = RCTX_S_FREE;
|
|
||||||
TRACE_DEBUG("SMALL req_ctx[%02i] initialized at %p, Data: %p => %p\r\n",
|
|
||||||
i, req_ctx + i, req_ctx[i].data, req_ctx[i].data + RCTX_SIZE_SMALL);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (; i < NUM_REQ_CTX; i++) {
|
|
||||||
req_ctx[i].size = RCTX_SIZE_LARGE;
|
|
||||||
req_ctx[i].tot_len = 0;
|
|
||||||
req_ctx[i].data = rctx_data_large[i];
|
|
||||||
req_ctx[i].state = RCTX_S_FREE;
|
|
||||||
TRACE_DEBUG("LARGE req_ctx[%02i] initialized at %p, Data: %p => %p\r\n",
|
|
||||||
i, req_ctx + i, req_ctx[i].data, req_ctx[i].data + RCTX_SIZE_LARGE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
76
firmware/libcommon/source/usb_buf.c
Normal file
76
firmware/libcommon/source/usb_buf.c
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
#include "board.h"
|
||||||
|
#include "trace.h"
|
||||||
|
#include "usb_buf.h"
|
||||||
|
|
||||||
|
#include "osmocom/core/linuxlist.h"
|
||||||
|
#include "osmocom/core/msgb.h"
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#define USB_ALLOC_SIZE 280
|
||||||
|
|
||||||
|
static struct usb_buffered_ep usb_buffered_ep[BOARD_USB_NUMENDPOINTS];
|
||||||
|
|
||||||
|
struct usb_buffered_ep *usb_get_buf_ep(uint8_t ep)
|
||||||
|
{
|
||||||
|
if (ep >= ARRAY_SIZE(usb_buffered_ep))
|
||||||
|
return NULL;
|
||||||
|
return &usb_buffered_ep[ep];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* User API
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
struct llist_head *usb_get_queue(uint8_t ep)
|
||||||
|
{
|
||||||
|
struct usb_buffered_ep *bep = usb_get_buf_ep(ep);
|
||||||
|
if (!bep)
|
||||||
|
return NULL;
|
||||||
|
return &bep->queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate a USB buffer for use with given end-point */
|
||||||
|
struct msgb *usb_buf_alloc(uint8_t ep)
|
||||||
|
{
|
||||||
|
struct msgb *msg;
|
||||||
|
|
||||||
|
msg = msgb_alloc(USB_ALLOC_SIZE, "USB");
|
||||||
|
if (!msg)
|
||||||
|
return NULL;
|
||||||
|
msg->dst = usb_get_buf_ep(ep);
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* release/return the USB buffer to the pool */
|
||||||
|
void usb_buf_free(struct msgb *msg)
|
||||||
|
{
|
||||||
|
msgb_free(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* submit a USB buffer for transmission to host */
|
||||||
|
int usb_buf_submit(struct msgb *msg)
|
||||||
|
{
|
||||||
|
struct usb_buffered_ep *ep = msg->dst;
|
||||||
|
|
||||||
|
if (!msg->dst) {
|
||||||
|
TRACE_ERROR("%s: msg without dst\r\n", __func__);
|
||||||
|
usb_buf_free(msg);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* no need for irqsafe operation, as the usb_tx_queue is
|
||||||
|
* processed only by the main loop context */
|
||||||
|
msgb_enqueue(&ep->queue, msg);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void usb_buf_init(void)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(usb_buffered_ep); i++) {
|
||||||
|
struct usb_buffered_ep *ep = &usb_buffered_ep[i];
|
||||||
|
INIT_LLIST_HEAD(&ep->queue);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
CFLAGS=-g -Wall -I../src_simtrace -I../libcommon/include -I.
|
CFLAGS=-g -Wall -I../src_simtrace -I../libcommon/include -I.
|
||||||
|
LDFLAGS=-losmocore
|
||||||
|
|
||||||
VPATH=../src_simtrace ../libcommon/source
|
VPATH=../src_simtrace ../libcommon/source
|
||||||
|
|
||||||
card_emu_test: card_emu_tests.hobj card_emu.hobj req_ctx.hobj iso7816_fidi.hobj
|
card_emu_test: card_emu_tests.hobj card_emu.hobj usb_buf.hobj iso7816_fidi.hobj
|
||||||
$(CC) $(LDFLAGS) -o $@ $^
|
$(CC) $(LDFLAGS) -o $@ $^
|
||||||
|
|
||||||
%.hobj: %.c
|
%.hobj: %.c
|
||||||
|
|||||||
@@ -7,7 +7,11 @@
|
|||||||
#include "card_emu.h"
|
#include "card_emu.h"
|
||||||
#include "cardemu_prot.h"
|
#include "cardemu_prot.h"
|
||||||
#include "tc_etu.h"
|
#include "tc_etu.h"
|
||||||
#include "req_ctx.h"
|
#include "usb_buf.h"
|
||||||
|
|
||||||
|
#define PHONE_DATAIN 1
|
||||||
|
#define PHONE_INT 2
|
||||||
|
#define PHONE_DATAOUT 3
|
||||||
|
|
||||||
/* stub functions required by card_emu.c */
|
/* stub functions required by card_emu.c */
|
||||||
|
|
||||||
@@ -128,17 +132,20 @@ static void reader_send_bytes(struct card_handle *ch, const uint8_t *bytes, unsi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dump_rctx(struct req_ctx *rctx)
|
static void dump_rctx(struct msgb *msg)
|
||||||
{
|
{
|
||||||
struct cardemu_usb_msg_hdr *mh =
|
struct cardemu_usb_msg_hdr *mh =
|
||||||
(struct cardemu_usb_msg_hdr *) rctx->data;
|
(struct cardemu_usb_msg_hdr *) msg->l1h;
|
||||||
struct cardemu_usb_msg_rx_data *rxd;
|
struct cardemu_usb_msg_rx_data *rxd;
|
||||||
int i;
|
int i;
|
||||||
|
#if 0
|
||||||
|
|
||||||
printf("req_ctx(%p): state=%u, size=%u, tot_len=%u, idx=%u, data=%p\n",
|
printf("req_ctx(%p): state=%u, size=%u, tot_len=%u, idx=%u, data=%p\n",
|
||||||
rctx, rctx->state, rctx->size, rctx->tot_len, rctx->idx, rctx->data);
|
rctx, rctx->state, rctx->size, rctx->tot_len, rctx->idx, rctx->data);
|
||||||
printf(" msg_type=%u, seq_nr=%u, msg_len=%u\n",
|
printf(" msg_type=%u, seq_nr=%u, msg_len=%u\n",
|
||||||
mh->msg_type, mh->seq_nr, mh->msg_len);
|
mh->msg_type, mh->seq_nr, mh->msg_len);
|
||||||
|
#endif
|
||||||
|
printf("%s\n", msgb_hexdump(msg));
|
||||||
|
|
||||||
switch (mh->msg_type) {
|
switch (mh->msg_type) {
|
||||||
case CEMU_USB_MSGT_DO_RX_DATA:
|
case CEMU_USB_MSGT_DO_RX_DATA:
|
||||||
@@ -151,23 +158,28 @@ static void dump_rctx(struct req_ctx *rctx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_and_verify_rctx(int state, const uint8_t *data, unsigned int len)
|
static void get_and_verify_rctx(uint8_t ep, const uint8_t *data, unsigned int len)
|
||||||
{
|
{
|
||||||
struct req_ctx *rctx;
|
struct llist_head *queue = usb_get_queue(ep);
|
||||||
|
struct msgb *msg;
|
||||||
struct cardemu_usb_msg_tx_data *td;
|
struct cardemu_usb_msg_tx_data *td;
|
||||||
struct cardemu_usb_msg_rx_data *rd;
|
struct cardemu_usb_msg_rx_data *rd;
|
||||||
|
struct cardemu_usb_msg_hdr *mh;
|
||||||
|
|
||||||
rctx = req_ctx_find_get(0, state, RCTX_S_USB_TX_BUSY);
|
assert(queue);
|
||||||
assert(rctx);
|
msg = msgb_dequeue(queue);
|
||||||
dump_rctx(rctx);
|
assert(msg);
|
||||||
|
dump_rctx(msg);
|
||||||
|
assert(msg->l1h);
|
||||||
|
mh = (struct cardemu_usb_msg_hdr *) msg->l1h;
|
||||||
|
|
||||||
/* verify the contents of the rctx */
|
/* verify the contents of the rctx */
|
||||||
switch (state) {
|
switch (mh->msg_type) {
|
||||||
case RCTX_S_USB_TX_PENDING:
|
case CEMU_USB_MSGT_DO_RX_DATA:
|
||||||
td = (struct cardemu_usb_msg_tx_data *) rctx->data;
|
rd = (struct cardemu_usb_msg_rx_data *) msg->l1h;
|
||||||
assert(td->hdr.msg_type == CEMU_USB_MSGT_DO_RX_DATA);
|
assert(rd->hdr.msg_type == CEMU_USB_MSGT_DO_RX_DATA);
|
||||||
assert(td->data_len == len);
|
assert(rd->data_len == len);
|
||||||
assert(!memcmp(td->data, data, len));
|
assert(!memcmp(rd->data, data, len));
|
||||||
break;
|
break;
|
||||||
#if 0
|
#if 0
|
||||||
case RCTX_S_UART_RX_PENDING:
|
case RCTX_S_UART_RX_PENDING:
|
||||||
@@ -181,55 +193,62 @@ static void get_and_verify_rctx(int state, const uint8_t *data, unsigned int len
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* free the req_ctx, indicating it has fully arrived on the host */
|
/* free the req_ctx, indicating it has fully arrived on the host */
|
||||||
req_ctx_set_state(rctx, RCTX_S_FREE);
|
usb_buf_free(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_and_verify_rctx_pps(const uint8_t *data, unsigned int len)
|
static void get_and_verify_rctx_pps(const uint8_t *data, unsigned int len)
|
||||||
{
|
{
|
||||||
struct req_ctx *rctx;
|
struct llist_head *queue = usb_get_queue(PHONE_DATAIN);
|
||||||
|
struct msgb *msg;
|
||||||
struct cardemu_usb_msg_pts_info *ptsi;
|
struct cardemu_usb_msg_pts_info *ptsi;
|
||||||
|
|
||||||
rctx = req_ctx_find_get(0, RCTX_S_USB_TX_PENDING, RCTX_S_USB_TX_BUSY);
|
assert(queue);
|
||||||
assert(rctx);
|
msg = msgb_dequeue(queue);
|
||||||
dump_rctx(rctx);
|
assert(msg);
|
||||||
|
dump_rctx(msg);
|
||||||
|
assert(msg->l1h);
|
||||||
|
|
||||||
ptsi = (struct cardemu_usb_msg_pts_info *) rctx->data;
|
ptsi = (struct cardemu_usb_msg_pts_info *) msg->l1h;
|
||||||
/* FIXME: verify */
|
/* FIXME: verify */
|
||||||
assert(ptsi->hdr.msg_type == CEMU_USB_MSGT_DO_PTS);
|
assert(ptsi->hdr.msg_type == CEMU_USB_MSGT_DO_PTS);
|
||||||
assert(!memcmp(ptsi->req, data, len));
|
assert(!memcmp(ptsi->req, data, len));
|
||||||
assert(!memcmp(ptsi->resp, data, len));
|
assert(!memcmp(ptsi->resp, data, len));
|
||||||
|
|
||||||
/* free the req_ctx, indicating it has fully arrived on the host */
|
/* free the req_ctx, indicating it has fully arrived on the host */
|
||||||
req_ctx_set_state(rctx, RCTX_S_FREE);
|
usb_buf_free(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* emulate a TPDU header being sent by the reader/phone */
|
/* emulate a TPDU header being sent by the reader/phone */
|
||||||
static void rdr_send_tpdu_hdr(struct card_handle *ch, const uint8_t *tpdu_hdr)
|
static void rdr_send_tpdu_hdr(struct card_handle *ch, const uint8_t *tpdu_hdr)
|
||||||
{
|
{
|
||||||
|
struct llist_head *queue = usb_get_queue(PHONE_DATAIN);
|
||||||
|
|
||||||
/* we don't want a receive context to become available during
|
/* we don't want a receive context to become available during
|
||||||
* the first four bytes */
|
* the first four bytes */
|
||||||
reader_send_bytes(ch, tpdu_hdr, 4);
|
reader_send_bytes(ch, tpdu_hdr, 4);
|
||||||
assert(!req_ctx_find_get(0, RCTX_S_USB_TX_PENDING, RCTX_S_USB_TX_BUSY));
|
assert(llist_empty(queue));
|
||||||
|
|
||||||
reader_send_bytes(ch, tpdu_hdr+4, 1);
|
reader_send_bytes(ch, tpdu_hdr+4, 1);
|
||||||
/* but then after the final byte of the TPDU header, we want a
|
/* but then after the final byte of the TPDU header, we want a
|
||||||
* receive context to be available for USB transmission */
|
* receive context to be available for USB transmission */
|
||||||
get_and_verify_rctx(RCTX_S_USB_TX_PENDING, tpdu_hdr, 5);
|
get_and_verify_rctx(PHONE_DATAIN, tpdu_hdr, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* emulate a CEMU_USB_MSGT_DT_TX_DATA received from USB */
|
/* emulate a CEMU_USB_MSGT_DT_TX_DATA received from USB */
|
||||||
static void host_to_device_data(const uint8_t *data, uint16_t len, unsigned int flags)
|
static void host_to_device_data(struct card_handle *ch, const uint8_t *data, uint16_t len,
|
||||||
|
unsigned int flags)
|
||||||
{
|
{
|
||||||
struct req_ctx *rctx;
|
struct msgb *msg;
|
||||||
struct cardemu_usb_msg_tx_data *rd;
|
struct cardemu_usb_msg_tx_data *rd;
|
||||||
|
struct llist_head *queue;
|
||||||
|
|
||||||
/* allocate a free req_ctx */
|
/* allocate a free req_ctx */
|
||||||
rctx = req_ctx_find_get(0, RCTX_S_FREE, RCTX_S_USB_RX_BUSY);
|
msg = usb_buf_alloc(PHONE_DATAOUT);
|
||||||
assert(rctx);
|
assert(msg);
|
||||||
|
msg->l1h = msg->head;
|
||||||
|
|
||||||
/* initialize the header */
|
/* initialize the header */
|
||||||
rd = (struct cardemu_usb_msg_tx_data *) rctx->data;
|
rd = (struct cardemu_usb_msg_tx_data *) msgb_put(msg, sizeof(*rd) + len);
|
||||||
rctx->tot_len = sizeof(*rd) + len;
|
|
||||||
cardemu_hdr_set(&rd->hdr, CEMU_USB_MSGT_DT_TX_DATA);
|
cardemu_hdr_set(&rd->hdr, CEMU_USB_MSGT_DT_TX_DATA);
|
||||||
rd->flags = flags;
|
rd->flags = flags;
|
||||||
/* copy data and set length */
|
/* copy data and set length */
|
||||||
@@ -238,7 +257,9 @@ static void host_to_device_data(const uint8_t *data, uint16_t len, unsigned int
|
|||||||
rd->hdr.msg_len = sizeof(*rd) + len;
|
rd->hdr.msg_len = sizeof(*rd) + len;
|
||||||
|
|
||||||
/* hand the req_ctx to the UART transmit code */
|
/* hand the req_ctx to the UART transmit code */
|
||||||
req_ctx_set_state(rctx, RCTX_S_UART_TX_PENDING);
|
queue = card_emu_get_uart_tx_queue(ch);
|
||||||
|
assert(queue);
|
||||||
|
msgb_enqueue(queue, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* card-transmit any pending characters */
|
/* card-transmit any pending characters */
|
||||||
@@ -270,7 +291,7 @@ test_tpdu_reader2card(struct card_handle *ch, const uint8_t *hdr, const uint8_t
|
|||||||
card_tx_verify_chars(ch, NULL, 0);
|
card_tx_verify_chars(ch, NULL, 0);
|
||||||
|
|
||||||
/* card emulator PC sends a singly byte PB response via USB */
|
/* card emulator PC sends a singly byte PB response via USB */
|
||||||
host_to_device_data(hdr+1, 1, CEMU_DATA_F_FINAL | CEMU_DATA_F_PB_AND_RX);
|
host_to_device_data(ch, hdr+1, 1, CEMU_DATA_F_FINAL | CEMU_DATA_F_PB_AND_RX);
|
||||||
/* card actually sends that single PB */
|
/* card actually sends that single PB */
|
||||||
card_tx_verify_chars(ch, hdr+1, 1);
|
card_tx_verify_chars(ch, hdr+1, 1);
|
||||||
|
|
||||||
@@ -278,13 +299,13 @@ test_tpdu_reader2card(struct card_handle *ch, const uint8_t *hdr, const uint8_t
|
|||||||
reader_send_bytes(ch, body, body_len);
|
reader_send_bytes(ch, body, body_len);
|
||||||
|
|
||||||
/* check if we have received them on the USB side */
|
/* check if we have received them on the USB side */
|
||||||
get_and_verify_rctx(RCTX_S_USB_TX_PENDING, body, body_len);
|
get_and_verify_rctx(PHONE_DATAIN, body, body_len);
|
||||||
|
|
||||||
/* ensure there is no extra data received on usb */
|
/* ensure there is no extra data received on usb */
|
||||||
assert(!req_ctx_find_get(0, RCTX_S_USB_TX_PENDING, RCTX_S_USB_TX_BUSY));
|
assert(llist_empty(usb_get_queue(PHONE_DATAOUT)));
|
||||||
|
|
||||||
/* card emulator sends SW via USB */
|
/* card emulator sends SW via USB */
|
||||||
host_to_device_data(tpdu_pb_sw, sizeof(tpdu_pb_sw),
|
host_to_device_data(ch, tpdu_pb_sw, sizeof(tpdu_pb_sw),
|
||||||
CEMU_DATA_F_FINAL | CEMU_DATA_F_PB_AND_TX);
|
CEMU_DATA_F_FINAL | CEMU_DATA_F_PB_AND_TX);
|
||||||
/* obtain any pending tx chars */
|
/* obtain any pending tx chars */
|
||||||
card_tx_verify_chars(ch, tpdu_pb_sw, sizeof(tpdu_pb_sw));
|
card_tx_verify_chars(ch, tpdu_pb_sw, sizeof(tpdu_pb_sw));
|
||||||
@@ -304,21 +325,21 @@ test_tpdu_card2reader(struct card_handle *ch, const uint8_t *hdr, const uint8_t
|
|||||||
card_tx_verify_chars(ch, NULL, 0);
|
card_tx_verify_chars(ch, NULL, 0);
|
||||||
|
|
||||||
/* card emulator PC sends a response PB via USB */
|
/* card emulator PC sends a response PB via USB */
|
||||||
host_to_device_data(hdr+1, 1, CEMU_DATA_F_PB_AND_TX);
|
host_to_device_data(ch, hdr+1, 1, CEMU_DATA_F_PB_AND_TX);
|
||||||
|
|
||||||
/* card actually sends that PB */
|
/* card actually sends that PB */
|
||||||
card_tx_verify_chars(ch, hdr+1, 1);
|
card_tx_verify_chars(ch, hdr+1, 1);
|
||||||
|
|
||||||
/* emulate more characters from card to reader */
|
/* emulate more characters from card to reader */
|
||||||
host_to_device_data(body, body_len, 0);
|
host_to_device_data(ch, body, body_len, 0);
|
||||||
/* obtain those bytes as they arrvive on the card */
|
/* obtain those bytes as they arrvive on the card */
|
||||||
card_tx_verify_chars(ch, body, body_len);
|
card_tx_verify_chars(ch, body, body_len);
|
||||||
|
|
||||||
/* ensure there is no extra data received on usb */
|
/* ensure there is no extra data received on usb */
|
||||||
assert(!req_ctx_find_get(0, RCTX_S_USB_TX_PENDING, RCTX_S_USB_TX_BUSY));
|
assert(llist_empty(usb_get_queue(PHONE_DATAOUT)));
|
||||||
|
|
||||||
/* card emulator sends SW via USB */
|
/* card emulator sends SW via USB */
|
||||||
host_to_device_data(tpdu_pb_sw, sizeof(tpdu_pb_sw), CEMU_DATA_F_FINAL);
|
host_to_device_data(ch, tpdu_pb_sw, sizeof(tpdu_pb_sw), CEMU_DATA_F_FINAL);
|
||||||
|
|
||||||
/* obtain any pending tx chars */
|
/* obtain any pending tx chars */
|
||||||
card_tx_verify_chars(ch, tpdu_pb_sw, sizeof(tpdu_pb_sw));
|
card_tx_verify_chars(ch, tpdu_pb_sw, sizeof(tpdu_pb_sw));
|
||||||
@@ -363,11 +384,11 @@ int main(int argc, char **argv)
|
|||||||
struct card_handle *ch;
|
struct card_handle *ch;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
req_ctx_init();
|
ch = card_emu_init(0, 23, 42, PHONE_DATAIN, PHONE_INT);
|
||||||
|
|
||||||
ch = card_emu_init(0, 23, 42);
|
|
||||||
assert(ch);
|
assert(ch);
|
||||||
|
|
||||||
|
usb_buf_init();
|
||||||
|
|
||||||
/* start up the card (VCC/RST, ATR) */
|
/* start up the card (VCC/RST, ATR) */
|
||||||
io_start_card(ch);
|
io_start_card(ch);
|
||||||
card_tx_verify_chars(ch, NULL, 0);
|
card_tx_verify_chars(ch, NULL, 0);
|
||||||
|
|||||||
Reference in New Issue
Block a user