This is merely a historical archive of years 2008-2021, before the migration to mailman3.
A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.
Hoernchen gerrit-no-reply at lists.osmocom.orgHoernchen has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-ccid-firmware/+/16267 ) Change subject: Add card_uart driver for ASF4 USART ...................................................................... Add card_uart driver for ASF4 USART Change-Id: Ic690055bc332ccca3de7c5f4429399cf9ff1d4da --- M ccid_common/ccid_slot_fsm.c M ccid_common/cuart.h A sysmoOCTSIM/cuart_driver_asf4_usart_async.c M sysmoOCTSIM/main.c 4 files changed, 525 insertions(+), 720 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-ccid-firmware refs/changes/67/16267/1 diff --git a/ccid_common/ccid_slot_fsm.c b/ccid_common/ccid_slot_fsm.c index a7ecb9f..870cf35 100644 --- a/ccid_common/ccid_slot_fsm.c +++ b/ccid_common/ccid_slot_fsm.c @@ -31,12 +31,18 @@ static struct iso_fsm_slot_instance g_si; -struct iso_fsm_slot *ccid_slot2iso_fsm_slot(struct ccid_slot *cs) +static struct iso_fsm_slot *ccid_slot2iso_fsm_slot(struct ccid_slot *cs) { OSMO_ASSERT(cs->slot_nr < ARRAY_SIZE(g_si.slot)); return &g_si.slot[cs->slot_nr]; } +struct card_uart *cuart4slot_nr(uint8_t slot_nr) +{ + OSMO_ASSERT(slot_nr < ARRAY_SIZE(g_si.slot)); + return g_si.slot[slot_nr].cuart; +} + static const uint8_t sysmousim_sjs1_atr[] = { 0x3B, 0x9F, 0x96, 0x80, 0x1F, 0xC7, 0x80, 0x31, 0xA0, 0x73, 0xBE, 0x21, 0x13, 0x67, 0x43, 0x20, @@ -74,9 +80,10 @@ osmo_fsm_inst_dispatch(ss->fi, ISO7816_E_POWER_UP_IND, NULL); cs->icc_powered = true; card_uart_ctrl(ss->cuart, CUART_CTL_CLOCK, true); - usleep(10000); - card_uart_ctrl(ss->cuart, CUART_CTL_RST, false); + delay_us(10000); + osmo_fsm_inst_dispatch(ss->fi, ISO7816_E_RESET_REL_IND, NULL); + card_uart_ctrl(ss->cuart, CUART_CTL_RST, false); msgb_free(msg); /* continues in iso_fsm_clot_user_cb once ATR is received */ @@ -145,8 +152,10 @@ if (enable) { card_uart_ctrl(ss->cuart, CUART_CTL_POWER, true); + cs->icc_powered = true; } else { card_uart_ctrl(ss->cuart, CUART_CTL_POWER, false); + cs->icc_powered = false; } } @@ -179,31 +188,35 @@ return 0; } - +extern void *g_tall_ctx; static int iso_fsm_slot_init(struct ccid_slot *cs) { - void *ctx = NULL; /* FIXME */ + void *ctx = g_tall_ctx; /* FIXME */ struct iso_fsm_slot *ss = ccid_slot2iso_fsm_slot(cs); struct card_uart *cuart = talloc_zero(ctx, struct card_uart); - char id_buf[16]; - char *devname = NULL; + char id_buf[16] = "SIM0"; + char devname[] = "foobar"; int rc; LOGPCS(cs, LOGL_DEBUG, "%s\n", __func__); /* HACK: make this in some way configurable so it works both in the firmware * and on the host (functionfs) */ - if (cs->slot_nr == 0) { - cs->icc_present = true; - devname = "/dev/ttyUSB5"; - } +// if (cs->slot_nr == 0) { +// cs->icc_present = true; +// devname = "/dev/ttyUSB5"; +// } + devname[0] = cs->slot_nr +0x30; + devname[1] = 0; + //sprintf(devname, "%d", cs->slot_nr); if (!cuart) return -ENOMEM; - snprintf(id_buf, sizeof(id_buf), "SIM%d", cs->slot_nr); + //snprintf(id_buf, sizeof(id_buf), "SIM%d", cs->slot_nr); + id_buf[3] = cs->slot_nr +0x30; if (devname) { - rc = card_uart_open(cuart, "tty", devname); + rc = card_uart_open(cuart, "asf4", devname); if (rc < 0) { LOGPCS(cs, LOGL_ERROR, "Cannot open UART %s: %d\n", devname, rc); talloc_free(cuart); diff --git a/ccid_common/cuart.h b/ccid_common/cuart.h index 951a3ec..5e397ab 100644 --- a/ccid_common/cuart.h +++ b/ccid_common/cuart.h @@ -7,6 +7,8 @@ #include <osmocom/core/select.h> #include "utils_ringbuffer.h" +struct usart_async_descriptor; + enum card_uart_event { /* a single byte was received, it's present at the (uint8_t *) data location */ CUART_E_RX_SINGLE, @@ -90,6 +92,10 @@ struct osmo_fd ofd; unsigned int baudrate; } tty; + struct { + struct usart_async_descriptor *usa_pd; + uint8_t slot_nr; + } asf4; } u; }; diff --git a/sysmoOCTSIM/cuart_driver_asf4_usart_async.c b/sysmoOCTSIM/cuart_driver_asf4_usart_async.c new file mode 100644 index 0000000..f9856f3 --- /dev/null +++ b/sysmoOCTSIM/cuart_driver_asf4_usart_async.c @@ -0,0 +1,402 @@ +/* Card (ICC) UART driver for the Atmel ASF4 asynchronous USART */ + +#include <errno.h> + +#include <osmocom/core/linuxlist.h> +#include <osmocom/core/utils.h> + +#include <hal_usart_async.h> +#include <utils_ringbuffer.h> +#include "driver_init.h" + +#include "ncn8025.h" + +#include "cuart.h" + +static struct usart_async_descriptor* SIM_peripheral_descriptors[] = {&SIM0, &SIM1, &SIM2, &SIM3, &SIM4, &SIM5, &SIM6, NULL}; + +extern struct card_uart *cuart4slot_nr(uint8_t slot_nr); + +/*********************************************************************** + * low-level helper routines + ***********************************************************************/ + +static void _SIM_rx_cb(const struct usart_async_descriptor *const io_descr, uint8_t slot_nr) +{ + struct card_uart *cuart = cuart4slot_nr(slot_nr); + int rc; + OSMO_ASSERT(cuart); + + if (cuart->rx_threshold == 1) { + /* bypass ringbuffer and report byte directly */ + uint8_t rx[1]; + rc = io_read((struct io_descriptor * const)&io_descr->io, rx, sizeof(rx)); + OSMO_ASSERT(rc == sizeof(rx)); + card_uart_notification(cuart, CUART_E_RX_SINGLE, rx); + } else { + /* go via ringbuffer and notify only after threshold */ + if (ringbuffer_num(&io_descr->rx) >= cuart->rx_threshold) + card_uart_notification(cuart, CUART_E_RX_COMPLETE, NULL); + } +} + +static void _SIM_tx_cb(const struct usart_async_descriptor *const io_descr, uint8_t slot_nr) +{ + struct card_uart *cuart = cuart4slot_nr(slot_nr); + OSMO_ASSERT(cuart); + card_uart_notification(cuart, CUART_E_TX_COMPLETE, io_descr->tx_buffer); +} + +#include <hpl_usart_async.h> +#include <hpl_usart_sync.h> + + +static void _SIM_error_cb(const struct usart_async_descriptor *const descr){ + volatile uint32_t status = hri_sercomusart_read_STATUS_reg(descr->device.hw); + volatile uint32_t data = hri_sercomusart_read_DATA_reg(descr->device.hw); + volatile uint32_t errrs = hri_sercomusart_read_RXERRCNT_reg(descr->device.hw); + OSMO_ASSERT(0 == 1) +} + +/* the below ugli-ness is required as the usart_async_descriptor doesn't have + * some kind of 'private' member that could provide the call-back anty kind of + * context */ +static void SIM0_rx_cb(const struct usart_async_descriptor *const io_descr) +{ + _SIM_rx_cb(io_descr, 0); +} +static void SIM1_rx_cb(const struct usart_async_descriptor *const io_descr) +{ + _SIM_rx_cb(io_descr, 1); +} +static void SIM2_rx_cb(const struct usart_async_descriptor *const io_descr) +{ + _SIM_rx_cb(io_descr, 2); +} +static void SIM3_rx_cb(const struct usart_async_descriptor *const io_descr) +{ + _SIM_rx_cb(io_descr, 3); +} +static void SIM4_rx_cb(const struct usart_async_descriptor *const io_descr) +{ + _SIM_rx_cb(io_descr, 4); +} +static void SIM5_rx_cb(const struct usart_async_descriptor *const io_descr) +{ + _SIM_rx_cb(io_descr, 5); +} +static void SIM6_rx_cb(const struct usart_async_descriptor *const io_descr) +{ + _SIM_rx_cb(io_descr, 6); +} +static void SIM7_rx_cb(const struct usart_async_descriptor *const io_descr) +{ + _SIM_rx_cb(io_descr, 7); +} +static usart_cb_t SIM_rx_cb[8] = { + SIM0_rx_cb, SIM1_rx_cb, SIM2_rx_cb, SIM3_rx_cb, + SIM4_rx_cb, SIM5_rx_cb, SIM6_rx_cb, SIM7_rx_cb, +}; +static void SIM0_tx_cb(const struct usart_async_descriptor *const io_descr) +{ + _SIM_tx_cb(io_descr, 0); +} +static void SIM1_tx_cb(const struct usart_async_descriptor *const io_descr) +{ + _SIM_tx_cb(io_descr, 1); +} +static void SIM2_tx_cb(const struct usart_async_descriptor *const io_descr) +{ + _SIM_tx_cb(io_descr, 2); +} +static void SIM3_tx_cb(const struct usart_async_descriptor *const io_descr) +{ + _SIM_tx_cb(io_descr, 3); +} +static void SIM4_tx_cb(const struct usart_async_descriptor *const io_descr) +{ + _SIM_tx_cb(io_descr, 4); +} +static void SIM5_tx_cb(const struct usart_async_descriptor *const io_descr) +{ + _SIM_tx_cb(io_descr, 5); +} +static void SIM6_tx_cb(const struct usart_async_descriptor *const io_descr) +{ + _SIM_tx_cb(io_descr, 6); +} +static void SIM7_tx_cb(const struct usart_async_descriptor *const io_descr) +{ + _SIM_tx_cb(io_descr, 7); +} +static usart_cb_t SIM_tx_cb[8] = { + SIM0_tx_cb, SIM1_tx_cb, SIM2_tx_cb, SIM3_tx_cb, + SIM4_tx_cb, SIM5_tx_cb, SIM6_tx_cb, SIM7_tx_cb, +}; + +#include <math.h> +#include "atmel_start.h" +#include "atmel_start_pins.h" +#include "config/hpl_gclk_config.h" +#include "iso7816_3.h" + +/** possible clock sources for the SERCOM peripheral + * warning: the definition must match the GCLK configuration + */ +static const uint8_t sercom_glck_sources[] = {GCLK_PCHCTRL_GEN_GCLK2_Val, GCLK_PCHCTRL_GEN_GCLK4_Val, GCLK_PCHCTRL_GEN_GCLK6_Val}; + + /** possible clock frequencies in MHz for the SERCOM peripheral + * warning: the definition must match the GCLK configuration + */ +static const double sercom_glck_freqs[] = {100E6 / CONF_GCLK_GEN_2_DIV, 100E6 / CONF_GCLK_GEN_4_DIV, 120E6 / CONF_GCLK_GEN_6_DIV}; + +/** the GCLK ID for the SERCOM SIM peripherals + * @note: used as index for PCHCTRL + */ +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}; + + +/** change baud rate of card slot + * @param[in] slotnr slot number for which the baud rate should be set + * @param[in] baudrate baud rate in bps to set + * @return if the baud rate has been set, else a parameter is out of range + */ +static bool slot_set_baudrate(uint8_t slotnr, uint32_t baudrate) +{ + ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors)); + + // calculate the error corresponding to the clock sources + uint16_t bauds[ARRAY_SIZE(sercom_glck_freqs)]; + double errors[ARRAY_SIZE(sercom_glck_freqs)]; + for (uint8_t i = 0; i < ARRAY_SIZE(sercom_glck_freqs); i++) { + double freq = sercom_glck_freqs[i]; // remember possible SERCOM frequency + uint32_t min = freq/16. * (1. - 65535. / 65536.); // calculate the minimum baud rate for this frequency + uint32_t max = freq/16. * (1. - 1. / 65536.); // calculate the maximum baud rate for this frequency + if (baudrate < min || baudrate > max) { // baud rate it out of supported range + errors[i] = NAN; + } else { + uint16_t baud = round(65536. * (1. - 16. * (baudrate/freq))); + bauds[i] = baud; + double actual = freq/16. * (1. - baud / 65536.); + errors[i] = fabs(1.0 - (actual / baudrate)); + } + } + + // find the smallest error + uint8_t best = ARRAY_SIZE(sercom_glck_freqs); + for (uint8_t i = 0; i < ARRAY_SIZE(sercom_glck_freqs); i++) { + if (isnan(errors[i])) { + continue; + } + if (best >= ARRAY_SIZE(sercom_glck_freqs)) { + best = i; + } else if (errors[i] < errors[best]) { + best = i; + } + } + if (best >= ARRAY_SIZE(sercom_glck_freqs)) { // found no clock supporting this baud rate + return false; + } + + // set clock and baud rate + struct usart_async_descriptor* slot = SIM_peripheral_descriptors[slotnr]; // get slot + if (NULL == slot) { + return false; + } + printf("(%u) switching SERCOM clock to GCLK%u (freq = %lu kHz) and baud rate to %lu bps (baud = %u)\r\n", slotnr, (best + 1) * 2, (uint32_t)(round(sercom_glck_freqs[best] / 1000)), baudrate, bauds[best]); + while (!usart_async_is_tx_empty(slot)); // wait for transmission to complete (WARNING no timeout) + usart_async_disable(slot); // disable SERCOM peripheral + hri_gclk_clear_PCHCTRL_reg(GCLK, SIM_peripheral_GCLK_ID[slotnr], (1 << GCLK_PCHCTRL_CHEN_Pos)); // disable clock for this peripheral + while (hri_gclk_get_PCHCTRL_reg(GCLK, SIM_peripheral_GCLK_ID[slotnr], (1 << GCLK_PCHCTRL_CHEN_Pos))); // wait until clock is really disabled + // it does not seem we need to completely disable the peripheral using hri_mclk_clear_APBDMASK_SERCOMn_bit + hri_gclk_write_PCHCTRL_reg(GCLK, SIM_peripheral_GCLK_ID[slotnr], sercom_glck_sources[best] | (1 << GCLK_PCHCTRL_CHEN_Pos)); // set peripheral core clock and re-enable it + usart_async_set_baud_rate(slot, bauds[best]); // set the new baud rate + usart_async_enable(slot); // re-enable SERCOM peripheral + + return true; +} + +/** change ISO baud rate of card slot + * @param[in] slotnr slot number for which the baud rate should be set + * @param[in] clkdiv can clock divider + * @param[in] f clock rate conversion integer F + * @param[in] d baud rate adjustment factor D + * @return if the baud rate has been set, else a parameter is out of range + */ +static bool slot_set_isorate(uint8_t slotnr, enum ncn8025_sim_clkdiv clkdiv, uint16_t f, uint8_t d) +{ + // input checks + ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors)); + if (clkdiv != SIM_CLKDIV_1 && clkdiv != SIM_CLKDIV_2 && clkdiv != SIM_CLKDIV_4 && clkdiv != SIM_CLKDIV_8) { + return false; + } + if (!iso7816_3_valid_f(f)) { + return false; + } + if (!iso7816_3_valid_d(d)) { + return false; + } + + // set clockdiv + struct ncn8025_settings settings; + ncn8025_get(slotnr, &settings); + if (settings.clkdiv != clkdiv) { + settings.clkdiv = clkdiv; + ncn8025_set(slotnr, &settings); + } + + // calculate desired frequency + uint32_t freq = 20000000UL; // maximum frequency + switch (clkdiv) { + case SIM_CLKDIV_1: + freq /= 1; + break; + case SIM_CLKDIV_2: + freq /= 2; + break; + case SIM_CLKDIV_4: + freq /= 4; + break; + case SIM_CLKDIV_8: + freq /= 8; + break; + } + + // set baud rate + uint32_t baudrate = (freq * d) / f; // calculate actual baud rate + return slot_set_baudrate(slotnr, baudrate); // set baud rate +} + +/*********************************************************************** + * Interface with card_uart (cuart) core + ***********************************************************************/ + +/* forward-declaration */ +static struct card_uart_driver asf4_usart_driver; +static int asf4_usart_close(struct card_uart *cuart); + +static int asf4_usart_open(struct card_uart *cuart, const char *device_name) +{ + struct usart_async_descriptor *usa_pd; + int slot_nr = atoi(device_name); + + if (slot_nr >= ARRAY_SIZE(SIM_peripheral_descriptors)) + return -ENODEV; + usa_pd = SIM_peripheral_descriptors[slot_nr]; + if (!usa_pd) + return -ENODEV; + + cuart->u.asf4.usa_pd = usa_pd; + cuart->u.asf4.slot_nr = slot_nr; + + + usart_async_register_callback(usa_pd, USART_ASYNC_RXC_CB, SIM_rx_cb[slot_nr]); + usart_async_register_callback(usa_pd, USART_ASYNC_TXC_CB, SIM_tx_cb[slot_nr]); + usart_async_register_callback(usa_pd, USART_ASYNC_ERROR_CB, _SIM_error_cb); + usart_async_enable(usa_pd); + + // set USART baud rate to match the interface (f = 2.5 MHz) and card default settings (Fd = 372, Dd = 1) + slot_set_isorate(cuart->u.asf4.slot_nr, SIM_CLKDIV_8, ISO7816_3_DEFAULT_FD, ISO7816_3_DEFAULT_DD); + + return 0; +} + +static int asf4_usart_close(struct card_uart *cuart) +{ + struct usart_async_descriptor *usa_pd = cuart->u.asf4.usa_pd; + + OSMO_ASSERT(cuart->driver == &asf4_usart_driver); + + usart_async_disable(usa_pd); + + return 0; +} + +static int asf4_usart_async_tx(struct card_uart *cuart, const uint8_t *data, size_t len) +{ + struct usart_async_descriptor *usa_pd = cuart->u.asf4.usa_pd; + int rc; + + OSMO_ASSERT(cuart->driver == &asf4_usart_driver); + OSMO_ASSERT(usart_async_is_tx_empty(usa_pd)); + + rc = io_write(&usa_pd->io, data, len); + if (rc < 0) + return rc; + + cuart->tx_busy = true; + + return rc; +} + +static int asf4_usart_async_rx(struct card_uart *cuart, uint8_t *data, size_t len) +{ + struct usart_async_descriptor *usa_pd = cuart->u.asf4.usa_pd; + + OSMO_ASSERT(cuart->driver == &asf4_usart_driver); + + return io_read(&usa_pd->io, data, len); +} + +static int asf4_usart_ctrl(struct card_uart *cuart, enum card_uart_ctl ctl, int arg) +{ + struct ncn8025_settings settings; + Sercom *sercom = cuart->u.asf4.usa_pd->device.hw; + + switch (ctl) { + case CUART_CTL_RX: + if (arg){ + sercom->USART.CTRLB.bit.RXEN = 1; + sercom->USART.CTRLB.bit.TXEN = 0; + } else { + delay_us(100); + sercom->USART.CTRLB.bit.RXEN = 0; + sercom->USART.CTRLB.bit.TXEN = 1; + } + break; + case CUART_CTL_RST: + ncn8025_get(cuart->u.asf4.slot_nr, &settings); + settings.rstin = arg ? true : false; + ncn8025_set(cuart->u.asf4.slot_nr, &settings); + usart_async_flush_rx_buffer(cuart->u.asf4.usa_pd); + break; + case CUART_CTL_POWER: + ncn8025_get(cuart->u.asf4.slot_nr, &settings); + settings.cmdvcc = arg ? true : false; + settings.led = arg ? true : false; + settings.vsel = SIM_VOLT_5V0; + + // set USART baud rate to match the interface (f = 2.5 MHz) and card default settings (Fd = 372, Dd = 1) + if(arg) + slot_set_isorate(cuart->u.asf4.slot_nr, SIM_CLKDIV_8, ISO7816_3_DEFAULT_FD, ISO7816_3_DEFAULT_DD); + + ncn8025_set(cuart->u.asf4.slot_nr, &settings); + break; + case CUART_CTL_WTIME: + /* no driver-specific handling of this */ + break; + case CUART_CTL_CLOCK: + /* FIXME */ + default: + return -EINVAL; + } + return 0; +} + +static const struct card_uart_ops asf4_usart_ops = { + .open = asf4_usart_open, + .close = asf4_usart_close, + .async_tx = asf4_usart_async_tx, + .async_rx = asf4_usart_async_rx, + .ctrl = asf4_usart_ctrl, +}; + +static struct card_uart_driver asf4_usart_driver = { + .name = "asf4", + .ops = &asf4_usart_ops, +}; + +static __attribute__((constructor)) void on_dso_load_cuart_asf4(void) +{ + card_uart_driver_register(&asf4_usart_driver); +} diff --git a/sysmoOCTSIM/main.c b/sysmoOCTSIM/main.c index fed562b..059c99d 100644 --- a/sysmoOCTSIM/main.c +++ b/sysmoOCTSIM/main.c @@ -40,48 +40,11 @@ #include "command.h" -// TODO put declaration in more global file -// TODO for now SIM7 is not present because used for debug -static struct usart_async_descriptor* SIM_peripheral_descriptors[] = {&SIM0, &SIM1, &SIM2, &SIM3, &SIM4, &SIM5, &SIM6, NULL}; #include "ccid_device.h" #include "usb_descriptors.h" +extern struct ccid_slot_ops iso_fsm_slot_ops; +static struct ccid_instance g_ci; -/** number of bytes transmitted on the SIM peripheral */ -static volatile bool SIM_tx_count[8]; - -static void SIM_rx_cb(const struct usart_async_descriptor *const io_descr) -{ -} - -/** called when the transmission is complete - * e.g. this is when the byte has been sent and there is no data to transmit anymore - */ -static void SIM_tx_cb(const struct usart_async_descriptor *const io_descr) -{ - // find slotnr for corresponding USART - uint8_t slotnr; - for (slotnr = 0; slotnr < ARRAY_SIZE(SIM_peripheral_descriptors) && SIM_peripheral_descriptors[slotnr] != io_descr; slotnr++); - - // set flag - if (slotnr < ARRAY_SIZE(SIM_peripheral_descriptors)) { - SIM_tx_count[slotnr] = true; - } -} - -/** possible clock sources for the SERCOM peripheral - * warning: the definition must match the GCLK configuration - */ -static const uint8_t sercom_glck_sources[] = {GCLK_PCHCTRL_GEN_GCLK2_Val, GCLK_PCHCTRL_GEN_GCLK4_Val, GCLK_PCHCTRL_GEN_GCLK6_Val}; - -/** possible clock frequencies in MHz for the SERCOM peripheral - * warning: the definition must match the GCLK configuration - */ -static const double sercom_glck_freqs[] = {100E6 / CONF_GCLK_GEN_2_DIV, 100E6 / CONF_GCLK_GEN_4_DIV, 120E6 / CONF_GCLK_GEN_6_DIV}; - -/** the GCLK ID for the SERCOM SIM peripherals - * @note: used as index for PCHCTRL - */ -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); @@ -103,16 +66,6 @@ * (there are 8 inputs + traces to drive!) */ hri_port_set_PINCFG_DRVSTR_bit(PORT, 0, 11); - // enable SIM interfaces - for (uint8_t i = 0; i < ARRAY_SIZE(SIM_peripheral_descriptors); i++) { - if (NULL == SIM_peripheral_descriptors[i]) { - continue; - } - usart_async_register_callback(SIM_peripheral_descriptors[i], USART_ASYNC_RXC_CB, SIM_rx_cb); // required for RX to work, even if the callback does nothing - 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(); } @@ -201,7 +154,9 @@ struct msgb *msg; int rc; - OSMO_ASSERT(!ep_q->in_progress); + if (ep_q->in_progress) + return 0; + msg = msgb_dequeue_irqsafe(&ep_q->list); if (!msg) return 0; @@ -250,6 +205,7 @@ msg = msgb_dequeue_irqsafe(&g_ccid_s.free_q); if (!msg) return -1; + msgb_reset(msg); ep_q->in_progress = msg; rc = ccid_df_read_out(msgb_data(msg), msgb_tailroom(msg)); @@ -272,6 +228,7 @@ 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); + g_ccid_s.out_ep.in_progress = NULL; /* submit another [free] msgb to receive the next transfer */ submit_next_out(); @@ -343,8 +300,11 @@ struct msgb *msg; unsigned int i; - for (i = 0; i < 8; i++) - new_mask |= ncn8025_interrupt_level(i) << i; + for (i = 0; i < 8; i++){ + bool level = ncn8025_interrupt_level(i); + new_mask |= level << i; + g_ci.slot[i].icc_present = level; + } /* notify the user/host about any changes */ if (g_ccid_s.card_insert_mask != new_mask) { @@ -363,629 +323,6 @@ * Command Line interface ***********************************************************************/ -static int validate_slotnr(int argc, char **argv, int idx) -{ - int slotnr; - if (argc < idx+1) { - printf("You have to specify the slot number (0..7)\r\n"); - return -1; - } - slotnr = atoi(argv[idx]); - if (slotnr < 0 || slotnr > 7) { - printf("You have to specify the slot number (0..7)\r\n"); - return -1; - } - return slotnr; -} - -/** change baud rate of card slot - * @param[in] slotnr slot number for which the baud rate should be set - * @param[in] baudrate baud rate in bps to set - * @return if the baud rate has been set, else a parameter is out of range - */ -static bool slot_set_baudrate(uint8_t slotnr, uint32_t baudrate) -{ - ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors)); - - // calculate the error corresponding to the clock sources - uint16_t bauds[ARRAY_SIZE(sercom_glck_freqs)]; - double errors[ARRAY_SIZE(sercom_glck_freqs)]; - for (uint8_t i = 0; i < ARRAY_SIZE(sercom_glck_freqs); i++) { - double freq = sercom_glck_freqs[i]; // remember possible SERCOM frequency - uint32_t min = freq / (2 * (255 + 1)); // calculate the minimum baud rate for this frequency - uint32_t max = freq / (2 * (0 + 1)); // calculate the maximum baud rate for this frequency - if (baudrate < min || baudrate > max) { // baud rate it out of supported range - errors[i] = NAN; - } else { - uint16_t baud = round(freq / (2 * baudrate) - 1); - bauds[i] = baud; - double actual = freq / (2 * (baud + 1)); - errors[i] = fabs(1.0 - (actual / baudrate)); - } - } - - // find the smallest error - uint8_t best = ARRAY_SIZE(sercom_glck_freqs); - for (uint8_t i = 0; i < ARRAY_SIZE(sercom_glck_freqs); i++) { - if (isnan(errors[i])) { - continue; - } - if (best >= ARRAY_SIZE(sercom_glck_freqs)) { - best = i; - } else if (errors[i] < errors[best]) { - best = i; - } - } - if (best >= ARRAY_SIZE(sercom_glck_freqs)) { // found no clock supporting this baud rate - return false; - } - - // set clock and baud rate - struct usart_async_descriptor* slot = SIM_peripheral_descriptors[slotnr]; // get slot - if (NULL == slot) { - return false; - } - printf("(%u) switching SERCOM clock to GCLK%u (freq = %lu kHz) and baud rate to %lu bps (baud = %u)\r\n", slotnr, (best + 1) * 2, (uint32_t)(round(sercom_glck_freqs[best] / 1000)), baudrate, bauds[best]); - while (!usart_async_is_tx_empty(slot)); // wait for transmission to complete (WARNING no timeout) - usart_async_disable(slot); // disable SERCOM peripheral - hri_gclk_clear_PCHCTRL_reg(GCLK, SIM_peripheral_GCLK_ID[slotnr], (1 << GCLK_PCHCTRL_CHEN_Pos)); // disable clock for this peripheral - while (hri_gclk_get_PCHCTRL_reg(GCLK, SIM_peripheral_GCLK_ID[slotnr], (1 << GCLK_PCHCTRL_CHEN_Pos))); // wait until clock is really disabled - // it does not seem we need to completely disable the peripheral using hri_mclk_clear_APBDMASK_SERCOMn_bit - hri_gclk_write_PCHCTRL_reg(GCLK, SIM_peripheral_GCLK_ID[slotnr], sercom_glck_sources[best] | (1 << GCLK_PCHCTRL_CHEN_Pos)); // set peripheral core clock and re-enable it - usart_async_set_baud_rate(slot, bauds[best]); // set the new baud rate - usart_async_enable(slot); // re-enable SERCOM peripheral - - return true; -} - -/** change ISO baud rate of card slot - * @param[in] slotnr slot number for which the baud rate should be set - * @param[in] clkdiv can clock divider - * @param[in] f clock rate conversion integer F - * @param[in] d baud rate adjustment factor D - * @return if the baud rate has been set, else a parameter is out of range - */ -static bool slot_set_isorate(uint8_t slotnr, enum ncn8025_sim_clkdiv clkdiv, uint16_t f, uint8_t d) -{ - // input checks - ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors)); - if (clkdiv != SIM_CLKDIV_1 && clkdiv != SIM_CLKDIV_2 && clkdiv != SIM_CLKDIV_4 && clkdiv != SIM_CLKDIV_8) { - return false; - } - if (!iso7816_3_valid_f(f)) { - return false; - } - if (!iso7816_3_valid_d(d)) { - return false; - } - - // set clockdiv - struct ncn8025_settings settings; - ncn8025_get(slotnr, &settings); - if (settings.clkdiv != clkdiv) { - settings.clkdiv = clkdiv; - ncn8025_set(slotnr, &settings); - } - - // calculate desired frequency - uint32_t freq = 20000000UL; // maximum frequency - switch (clkdiv) { - case SIM_CLKDIV_1: - freq /= 1; - break; - case SIM_CLKDIV_2: - freq /= 2; - break; - case SIM_CLKDIV_4: - freq /= 4; - break; - case SIM_CLKDIV_8: - freq /= 8; - break; - } - - // set baud rate - uint32_t baudrate = (freq * d) / f; // calculate actual baud rate - return slot_set_baudrate(slotnr, baudrate); // set baud rate -} - -/** write data to card - * @param[in] slotnr slot number on which to send data - * @param[in] data data to be transmitted - * @param[in] length length of data to be transmitted - * @return error code - */ -static int slot_card_write(uint8_t slotnr, const uint8_t* data, uint16_t length) -{ - // input checks - ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors)); - if (0 == length || NULL == data) { - return ERR_INVALID_ARG; - } - - struct usart_async_descriptor* sim = SIM_peripheral_descriptors[slotnr]; - ((Sercom *)sim->device.hw)->USART.CTRLB.bit.RXEN = 0; // disable receive (to avoid the echo back) - SIM_tx_count[slotnr] = false; // reset TX complete - for (uint16_t i = 0; i < length; i++) { // transmit data - while(!usart_async_is_tx_empty(sim)); // wait for previous byte to be transmitted (WARNING blocking) - if (1 != io_write(&sim->io, &data[i], 1)) { // put but in transmit buffer - return ERR_IO; - } - } - while (!SIM_tx_count[slotnr]); // wait until transmission is complete (WARNING blocking) - ((Sercom *)sim->device.hw)->USART.CTRLB.bit.RXEN = 1; // enable receive again - - return ERR_NONE; -} - -/** read data from card - * @param[in] slotnr slot number on which to send data - * @param[out] data buffer for read data to be stored - * @param[in] length length of data to be read - * @param[in] wt Waiting Time in ETU - * @return error code - * TODO fix WT/ETU duration - */ -static int slot_card_read(uint8_t slotnr, uint8_t* data, uint16_t length, uint32_t wt) -{ - // input checks - ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors)); - if (0 == length || NULL == data) { - return ERR_INVALID_ARG; - } - - struct usart_async_descriptor* sim = SIM_peripheral_descriptors[slotnr]; - - ((Sercom *)sim->device.hw)->USART.CTRLB.bit.RXEN = 1; // ensure RX is enabled - uint32_t timeout = wt; // reset waiting time - for (uint16_t i = 0; i < length; i++) { // read all data - while (timeout && !usart_async_is_rx_not_empty(sim)) { // verify if data is present - delay_us(149); // wait for 1 ETU (372 / 1 / 2.5 MHz = 148.8 us) - timeout--; - } - if (0 == timeout) { // timeout reached - return ERR_TIMEOUT; - } - timeout = wt; // reset waiting time - if (1 != io_read(&sim->io, &data[i], 1)) { // read one byte - return ERR_IO; - } - } - - return ERR_NONE; -} - -/** transfer TPDU - * @param[in] slotnr slot number on which to transfer the TPDU - * @param[in] header TPDU header to send - * @param[io] data TPDU data to transfer - * @param[in] data_length length of TPDU data to transfer - * @param[in] write if the data should be written (true) or read (false) - * TODO fix WT - * TODO the data length can be deduce from the header - */ -static int slot_tpdu_xfer(uint8_t slotnr, const uint8_t* header, uint8_t* data, uint16_t data_length, bool write) -{ - // input checks - ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors)); - if (NULL == header || (data_length > 0 && NULL == data)) { - return ERR_INVALID_ARG; - } - - int rc; - struct usart_async_descriptor* sim = SIM_peripheral_descriptors[slotnr]; // get USART peripheral - usart_async_flush_rx_buffer(sim); // flush RX buffer to start from scratch - - // send command header - printf("(%d) TPDU: ", slotnr); - for (uint8_t i = 0; i < 5; i++) { - printf("%02x ", header[i]); - } - rc = slot_card_write(slotnr, header, 5); // transmit header - if (ERR_NONE != rc) { - printf("error in command header transmit (errno = %d)\r\n", rc); - return rc; - } - - // read procedure byte, and handle data - uint8_t pb = 0x60; // wait more procedure byte - uint16_t data_i = 0; // progress in the data transfer - while (0x60 == pb) { // wait for SW - rc = slot_card_read(slotnr, &pb, 1, ISO7816_3_DEFAULT_WT); - if (ERR_NONE != rc) { - printf("error while receiving PB/SW1 (errno = %d)\r\n", rc); - return rc; - } - printf("%02x ", pb); - if (0x60 == pb) { // NULL byte - // just wait more time - } else if ((0x60 == (pb & 0xf0)) || (0x90 == (pb & 0xf0))) { // SW1 byte - // left the rest of the code handle it - } else if (header[1] == pb) { // ACK byte - // transfer rest of the data - if (data_i >= data_length) { - printf("error no more data to transfer\r\n"); - return ERR_INVALID_DATA; - } - if (write) { // transmit remaining command data - rc = slot_card_write(slotnr, &data[data_i], data_length - data_i); // transmit command data - if (ERR_NONE != rc) { - printf("error in command data transmit (errno = %d)\r\n", rc); - return rc; - } - } else { // receive remaining command data - rc = slot_card_read(slotnr, &data[data_i], data_length - data_i, ISO7816_3_DEFAULT_WT); - if (ERR_NONE != rc) { - printf("error in command data receive (errno = %d)\r\n", rc); - return rc; - } - } - for (uint16_t i = data_i; i < data_length; i++) { - printf("%02x ", data[i]); - } - data_i = data_length; // remember we transferred the data - pb = 0x60; // wait for SW1 - } else if (header[1] == (pb ^ 0xff)) { // ACK byte - // transfer only one byte - if (data_i >= data_length) { - printf("error no more data to transfer\r\n"); - return ERR_INVALID_DATA; - } - if (write) { // transmit command data byte - rc = slot_card_write(slotnr, &data[data_i], 1); // transmit command data - if (ERR_NONE != rc) { - printf("error in command data transmit (errno = %d)\r\n", rc); - return rc; - } - } else { // receive command data byte - rc = slot_card_read(slotnr, &data[data_i], 1, ISO7816_3_DEFAULT_WT); - if (ERR_NONE != rc) { - printf("error in command data receive (errno = %d)\r\n", rc); - return rc; - } - } - printf("%02x ", data[data_i]); - data_i += 1; // remember we transferred one data byte - pb = 0x60; // wait for SW1 - } else { // invalid byte - return ERR_INVALID_DATA; - } - } - - // read SW2 - uint8_t sw2; - rc = slot_card_read(slotnr, &sw2, 1, ISO7816_3_DEFAULT_WT); - if (ERR_NONE != rc) { - printf("error in receiving SW2 (errno = %d)\r\n", rc); - return rc; - } - printf("%02x", sw2); - - printf("\r\n"); - return ERR_NONE; -} - -DEFUN(sim_status, cmd_sim_status, "sim-status", "Get state of specified NCN8025") -{ - struct ncn8025_settings settings; - int slotnr = validate_slotnr(argc, argv, 1); - if (slotnr < 0) - return; - ncn8025_get(slotnr, &settings); - printf("SIM%d: ", slotnr); - ncn8025_dump(&settings); - printf("\r\n"); -} - -DEFUN(sim_power, cmd_sim_power, "sim-power", "Enable/disable SIM card power") -{ - struct ncn8025_settings settings; - int slotnr = validate_slotnr(argc, argv, 1); - int enable; - - if (slotnr < 0) - return; - - if (argc < 3) { - printf("You have to specify 0=disable or 1=enable\r\n"); - return; - } - enable = atoi(argv[2]); - ncn8025_get(slotnr, &settings); - if (enable) - settings.cmdvcc = true; - else - settings.cmdvcc = false; - ncn8025_set(slotnr, &settings); -} - -DEFUN(sim_reset, cmd_sim_reset, "sim-reset", "Enable/disable SIM reset") -{ - struct ncn8025_settings settings; - int slotnr = validate_slotnr(argc, argv, 1); - int enable; - - if (slotnr < 0) - return; - - if (argc < 3) { - printf("You have to specify 0=disable or 1=enable\r\n"); - return; - } - enable = atoi(argv[2]); - ncn8025_get(slotnr, &settings); - if (enable) - settings.rstin = true; - else - settings.rstin = false; - ncn8025_set(slotnr, &settings); -} - -DEFUN(sim_clkdiv, cmd_sim_clkdiv, "sim-clkdiv", "Set SIM clock divider (1,2,4,8)") -{ - struct ncn8025_settings settings; - int slotnr = validate_slotnr(argc, argv, 1); - int clkdiv; - - if (slotnr < 0) - return; - - if (argc < 3) { - printf("You have to specify a valid divider (1,2,4,8)\r\n"); - return; - } - clkdiv = atoi(argv[2]); - if (clkdiv != 1 && clkdiv != 2 && clkdiv != 4 && clkdiv != 8) { - printf("You have to specify a valid divider (1,2,4,8)\r\n"); - return; - } - ncn8025_get(slotnr, &settings); - switch (clkdiv) { - case 1: - settings.clkdiv = SIM_CLKDIV_1; - break; - case 2: - settings.clkdiv = SIM_CLKDIV_2; - break; - case 4: - settings.clkdiv = SIM_CLKDIV_4; - break; - case 8: - settings.clkdiv = SIM_CLKDIV_8; - break; - } - ncn8025_set(slotnr, &settings); -} - -DEFUN(sim_voltage, cmd_sim_voltage, "sim-voltage", "Set SIM voltage (5/3/1.8)") -{ - struct ncn8025_settings settings; - int slotnr = validate_slotnr(argc, argv, 1); - - if (slotnr < 0) - return; - - if (argc < 3) { - printf("You have to specify a valid voltage (5/3/1.8)\r\n"); - return; - } - ncn8025_get(slotnr, &settings); - if (!strcmp(argv[2], "5")) - settings.vsel = SIM_VOLT_5V0; - else if (!strcmp(argv[2], "3")) - settings.vsel = SIM_VOLT_3V0; - else if (!strcmp(argv[2], "1.8")) - settings.vsel = SIM_VOLT_1V8; - else { - printf("You have to specify a valid voltage (5/3/1.8)\r\n"); - return; - } - ncn8025_set(slotnr, &settings); -} - -DEFUN(sim_led, cmd_sim_led, "sim-led", "Set SIM LED (1=on, 0=off)") -{ - struct ncn8025_settings settings; - int slotnr = validate_slotnr(argc, argv, 1); - - if (slotnr < 0) - return; - - if (argc < 3) { - printf("You have to specify 0=disable or 1=enable\r\n"); - return; - } - ncn8025_get(slotnr, &settings); - if (atoi(argv[2])) - settings.led = true; - else - settings.led = false; - ncn8025_set(slotnr, &settings); -} - -DEFUN(sim_atr, cmd_sim_atr, "sim-atr", "Read ATR from SIM card") -{ - struct ncn8025_settings settings; - int slotnr = validate_slotnr(argc, argv, 1); - - if (slotnr < 0 || slotnr >= ARRAY_SIZE(SIM_peripheral_descriptors) || NULL == SIM_peripheral_descriptors[slotnr]) { - return; - } - - // check if card is present (and read current settings) - ncn8025_get(slotnr, &settings); - if (!settings.simpres) { - printf("(%d) error: no card present\r\n", slotnr); - return; - } - - // switch card off (assert reset and disable power) - // note: ISO/IEC 7816-3:2006 section 6.4 provides the deactivation sequence, but not the minimum corresponding times - settings.rstin = true; - settings.cmdvcc = false; - settings.led = true; - ncn8025_set(slotnr, &settings); - - // TODO wait some time for card to be completely deactivated - usart_async_flush_rx_buffer(SIM_peripheral_descriptors[slotnr]); // flush RX buffer to start from scratch - - - // set clock to lowest frequency (20 MHz / 8 = 2.5 MHz) - // note: according to ISO/IEC 7816-3:2006 section 5.2.3 the minimum value is 1 MHz, and maximum is 5 MHz during activation - settings.clkdiv = SIM_CLKDIV_8; - // set USART baud rate to match the interface (f = 2.5 MHz) and card default settings (Fd = 372, Dd = 1) - slot_set_isorate(slotnr, settings.clkdiv, ISO7816_3_DEFAULT_FD, ISO7816_3_DEFAULT_DD); - // set card voltage to 3.0 V (the most supported) - // note: according to ISO/IEC 7816-3:2006 no voltage should damage the card, and you should cycle from low to high - settings.vsel = SIM_VOLT_3V0; - // provide power (the NCN8025 should perform the activation according to spec) - // note: activation sequence is documented in ISO/IEC 7816-3:2006 section 6.2 - settings.cmdvcc = true; - ncn8025_set(slotnr, &settings); - - // wait for Tb=400 cycles before re-asserting reset - delay_us(400 * 10000 / 2500); // 400 cycles * 1000 for us, 2.5 MHz / 1000 for us - - // de-assert reset to switch card back on - settings.rstin = false; - ncn8025_set(slotnr, &settings); - - // wait for Tc=40000 cycles for transmission to start - uint32_t cycles = 40000; - while (cycles && !usart_async_is_rx_not_empty(SIM_peripheral_descriptors[slotnr])) { - delay_us(10); - cycles -= 25; // 10 us = 25 cycles at 2.5 MHz - } - if (!usart_async_is_rx_not_empty(SIM_peripheral_descriptors[slotnr])) { - delay_us(12 * 372 / 1 / 2); // wait more than one byte (approximate freq down to 2 MHz) - } - // verify if one byte has been received - if (!usart_async_is_rx_not_empty(SIM_peripheral_descriptors[slotnr])) { - printf("(%d) error: card not responsive\r\n", slotnr); - return; - } - - // read ATR (just do it until there is no traffic anymore) - // TODO the ATR should be parsed to read the right number of bytes, instead we just wait until to end of WT - printf("(%d) ATR: ", slotnr); - uint8_t atr_byte; - while (usart_async_is_rx_not_empty(SIM_peripheral_descriptors[slotnr])) { - if (1 == io_read(&SIM_peripheral_descriptors[slotnr]->io, &atr_byte, 1)) { - printf("%02x ", atr_byte); - } - uint16_t wt = ISO7816_3_DEFAULT_WT; // waiting time in ETU - while (wt && !usart_async_is_rx_not_empty(SIM_peripheral_descriptors[slotnr])) { - delay_us(149); // wait for 1 ETU (372 / 1 / 2.5 MHz = 148.8 us) - wt--; - } - } - printf("\r\n"); - - /* disable LED */ - settings.led = false; - ncn8025_set(slotnr, &settings); -} - -DEFUN(sim_iccid, cmd_sim_iccid, "sim-iccid", "Read ICCID from SIM card") -{ - struct ncn8025_settings settings; - int slotnr = validate_slotnr(argc, argv, 1); - - if (slotnr < 0 || slotnr >= ARRAY_SIZE(SIM_peripheral_descriptors) || NULL == SIM_peripheral_descriptors[slotnr]) { - return; - } - - // read current settings and check if card is present and powered - ncn8025_get(slotnr, &settings); - if (!settings.simpres) { - printf("(%d) error: no card present\r\n", slotnr); - return; - } - if (!settings.cmdvcc) { - printf("(%d) error: card not powered\r\n", slotnr); - return; - } - if (settings.rstin) { - printf("(%d) error: card under reset\r\n", slotnr); - return; - } - - // enable LED - if (!settings.led) { - settings.led = true; - ncn8025_set(slotnr, &settings); - } - - // select MF - printf("(%d) SELECT MF\r\n", slotnr); - const uint8_t select_header[] = {0xa0, 0xa4, 0x00, 0x00, 0x02}; // see TS 102.221 sec. 11.1.1 - const uint8_t select_data_mf[] = {0x3f, 0x00}; // see TS 102.221 sec. 13.1 - int rc = slot_tpdu_xfer(slotnr, select_header, (uint8_t*)select_data_mf, ARRAY_SIZE(select_data_mf), true); // transfer TPDU - if (ERR_NONE != rc) { - printf("error while SELECT MF (errno = %d)\r\n", rc); - } - // ignore response data - - // select EF_ICCID - printf("(%d) SELECT EF_ICCID\r\n", slotnr); - const uint8_t select_data_ef_iccid[] = {0x2f, 0xe2}; // see TS 102.221 sec. 13.2 - rc = slot_tpdu_xfer(slotnr, select_header, (uint8_t*)select_data_ef_iccid, ARRAY_SIZE(select_data_ef_iccid), true); // transfer TPDU - if (ERR_NONE != rc) { - printf("error while SELECT EF_ICCID (errno = %d)\r\n", rc); - } - // ignore response data - - // read EF_ICCID - printf("(%d) READ EF_ICCID\r\n", slotnr); - uint8_t iccid[10]; - uint8_t read_binary[] = {0xa0, 0xb0, 0x00, 0x00, ARRAY_SIZE(iccid)}; // see TS 102.221 sec. 11.1.3 - rc = slot_tpdu_xfer(slotnr, read_binary, iccid, ARRAY_SIZE(iccid), false); // transfer TPDU - if (ERR_NONE != rc) { - printf("error while READ ICCID (errno = %d)\r\n", rc); - } - // ignore response data - - printf("(%d) ICCID: ", slotnr); - for (uint8_t i = 0; i < ARRAY_SIZE(iccid); i++) { - uint8_t nibble = iccid[i] & 0xf; - if (0xf == nibble) { - break; - } - printf("%x", nibble); - nibble = iccid[i] >> 4; - if (0xf == nibble) { - break; - } - printf("%x", nibble); - } - printf("\r\n"); - - // disable LED - settings.led = false; - ncn8025_set(slotnr, &settings); -} - -DEFUN(get_time, cmd_get_time, "get-time", "Read Time from RTC") -{ - struct calendar_date_time dt; - calendar_get_date_time(&CALENDAR_0, &dt); - printf("%04u-%02u-%02u %02u:%02u:%02u\r\n", dt.date.year, dt.date.month, dt.date.day, - dt.time.hour, dt.time.min, dt.time.sec); -} - -#include <osmocom/core/timer.h> -static struct osmo_timer_list t; -static void tmr_cb(void *data) -{ - printf("timer fired!\r\n"); -} -DEFUN(test_timer, cmd_test_timer, "test-timer", "Test osmo_timer") -{ - printf("Setting up timer for 3s...\n\r"); - osmo_timer_setup(&t, &tmr_cb, NULL); - osmo_timer_schedule(&t, 3, 0); -} - extern void testmode_init(void); extern void libosmo_emb_init(void); @@ -993,25 +330,9 @@ #include "talloc.h" #include "logging.h" -#include <osmocom/core/msgb.h> + void *g_tall_ctx; -DEFUN(_talloc_report, cmd_talloc_report, "talloc-report", "Generate a talloc report") -{ - talloc_report_full(g_tall_ctx, stdout); -} - -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"); -} - -DEFUN(v_talloc_free, cmd_talloc_free, "talloc-free", "Release all memory") -{ - talloc_free(g_tall_ctx); - g_tall_ctx = NULL; -} /* Section 9.6 of SAMD5x/E5x Family Data Sheet */ static int get_chip_unique_serial(uint8_t *out, size_t len) @@ -1067,6 +388,55 @@ strcat(out, "BACKUP "); } +//####################### + + + +static uint32_t clock_freqs[] = { + 2500000 +}; + +static uint32_t data_rates[] = { + 6720 +}; +extern struct usb_desc_collection usb_fs_descs; + + + +static int feed_ccid(void) +{ + struct usb_ep_q *ep_q = &g_ccid_s.out_ep; + struct msgb *msg; + int rc; + + msg = msgb_dequeue_irqsafe(&g_ccid_s.out_ep.list); + if (!msg) + return -1; + + ccid_handle_out(&g_ci, msg); + return 1; +} + +static int ccid_ops_send_in(struct ccid_instance *ci, struct msgb *msg) +{ + /* add just-received msg to tail of endpoint queue */ + OSMO_ASSERT(msg); + + /* append to list of pending-to-be-handed messages */ + llist_add_tail_at(&msg->list, &g_ccid_s.in_ep.list); + submit_next_in(); + return 0; +} + +static const struct ccid_ops c_ops = { + .send_in = ccid_ops_send_in, + .send_int = 0, +}; + +//####################### + +#define NUM_OUT_BUF 7 + int main(void) { char sernr_buf[16*2+1]; @@ -1080,20 +450,6 @@ board_init(); command_init("sysmoOCTSIM> "); - command_register(&cmd_sim_status); - command_register(&cmd_sim_power); - command_register(&cmd_sim_reset); - command_register(&cmd_sim_clkdiv); - command_register(&cmd_sim_voltage); - command_register(&cmd_sim_led); - command_register(&cmd_sim_atr); - command_register(&cmd_sim_iccid); - testmode_init(); - command_register(&cmd_talloc_test); - command_register(&cmd_talloc_report); - command_register(&cmd_talloc_free); - command_register(&cmd_get_time); - command_register(&cmd_test_timer); printf("\r\n\r\n" "=============================================================================\n\r" @@ -1111,11 +467,39 @@ LOGP(DUSB, LOGL_ERROR, "foobar usb\n"); - command_print_prompt(); + ccid_instance_init(&g_ci, &c_ops, &iso_fsm_slot_ops, &usb_fs_descs.ccid.class, + data_rates, clock_freqs, "", 0); + + for(int i =0; i < NUM_OUT_BUF; i++){ + struct msgb *msg = msgb_alloc(300, "ccid"); + 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); + } + submit_next_out(); + +// command_print_prompt(); while (true) { // main loop command_try_recv(); poll_card_detect(); submit_next_irq(); + feed_ccid(); osmo_timers_update(); + int qs = llist_count_at(&g_ccid_s.free_q); + if(qs > NUM_OUT_BUF) + for (int i= 0; i < qs-NUM_OUT_BUF; i++){ + struct msgb *msg = msgb_dequeue_irqsafe(&g_ccid_s.free_q); + if (msg) + msgb_free(msg); + } + if(qs < NUM_OUT_BUF) + for (int i= 0; i < qs-NUM_OUT_BUF; i++){ + struct msgb *msg = msgb_alloc(300,"ccid"); + 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); + } + + } } -- To view, visit https://gerrit.osmocom.org/c/osmo-ccid-firmware/+/16267 To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: osmo-ccid-firmware Gerrit-Branch: master Gerrit-Change-Id: Ic690055bc332ccca3de7c5f4429399cf9ff1d4da Gerrit-Change-Number: 16267 Gerrit-PatchSet: 1 Gerrit-Owner: Hoernchen <ewild at sysmocom.de> Gerrit-MessageType: newchange -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20191127/8881e1b2/attachment.htm>