From 91f1f18b4864a9ed59b68f9e8350ebdcc8e1d0a3 Mon Sep 17 00:00:00 2001 From: Eric Wild Date: Wed, 11 Nov 2020 21:24:05 +0100 Subject: 7816 fsm/cuart: support inverse condition cards This does not currently work with "pcsc-lite version 1.8.26." because the inverse conditon cards I know do not support the PPS exchange, which according to spec leads to card deactivation, so the slots needs to be powered up again, which does not happen. osmo-sim-test works after manually disabling the pps exchange code in the firmware. Change-Id: I892e1d883825111cc1e4ea09589c4fdd256da03c --- ccid_common/ccid_slot_fsm.c | 14 ++++++++++---- ccid_common/cuart.h | 1 + ccid_common/iso7816_fsm.c | 15 ++++++++++++--- sysmoOCTSIM/cuart_driver_asf4_usart_async.c | 29 +++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+), 7 deletions(-) diff --git a/ccid_common/ccid_slot_fsm.c b/ccid_common/ccid_slot_fsm.c index a8c4e54..4cf75bc 100644 --- a/ccid_common/ccid_slot_fsm.c +++ b/ccid_common/ccid_slot_fsm.c @@ -204,10 +204,16 @@ static int iso_handle_fsm_events(struct ccid_slot *cs, bool enable){ break; case ISO7816_E_ATR_DONE_IND: tpdu = data; - LOGPCS(cs, LOGL_DEBUG, "%s(event=%d, data=%s)\n", __func__, event, - msgb_hexdump(tpdu)); - resp = ccid_gen_data_block(cs, ss->seq, CCID_CMD_STATUS_OK, 0, - msgb_data(tpdu), msgb_length(tpdu)); + + /* inverse condition, error interrupt is always disabled during atr and reenabled here after atr */ + if(*msgb_data(tpdu) == 0x3f) { + card_uart_ctrl(ss->cuart, CUART_CTL_ERROR_AND_INV, true); + } else { + card_uart_ctrl(ss->cuart, CUART_CTL_ERROR_AND_INV, false); + } + + LOGPCS(cs, LOGL_DEBUG, "%s(event=%d, data=%s)\n", __func__, event, msgb_hexdump(tpdu)); + resp = ccid_gen_data_block(cs, ss->seq, CCID_CMD_STATUS_OK, 0, msgb_data(tpdu), msgb_length(tpdu)); ccid_slot_send_unbusy(cs, resp); cs->event = 0; break; diff --git a/ccid_common/cuart.h b/ccid_common/cuart.h index e5ec501..c0a3a52 100644 --- a/ccid_common/cuart.h +++ b/ccid_common/cuart.h @@ -54,6 +54,7 @@ enum card_uart_ctl { CUART_CTL_SET_FD, CUART_CTL_GET_BAUDRATE, CUART_CTL_GET_CLOCK_FREQ, + CUART_CTL_ERROR_AND_INV, /* enable error interrupt and maybe inverse signalling according to arg */ }; struct card_uart; diff --git a/ccid_common/iso7816_fsm.c b/ccid_common/iso7816_fsm.c index e819e64..8e113b0 100644 --- a/ccid_common/iso7816_fsm.c +++ b/ccid_common/iso7816_fsm.c @@ -639,6 +639,15 @@ static uint8_t get_rx_byte_evt(struct osmo_fsm_inst *fi, void *data) struct iso7816_3_priv *ip = get_iso7816_3_priv(fi); uint8_t byte = *(uint8_t *)data; + return byte; +} + +/* obtain the 'byte' (possbily inverted) parameter of an ISO7816_E_RX event */ +static uint8_t get_atr_rx_byte_evt(struct osmo_fsm_inst *fi, void *data) +{ + struct iso7816_3_priv *ip = get_iso7816_3_priv(fi); + uint8_t byte = *(uint8_t *)data; + /* apply inverse convention */ if (ip->convention_convert) byte = convention_convert_lut[byte]; @@ -689,14 +698,14 @@ static void atr_wait_ts_action(struct osmo_fsm_inst *fi, uint32_t event, void *d case ISO7816_E_RX_SINGLE: OSMO_ASSERT(msgb_length(atp->atr) == 0); restart: - byte = get_rx_byte_evt(parent_fi, data); + byte = get_atr_rx_byte_evt(parent_fi, data); LOGPFSML(fi, LOGL_DEBUG, "RX byte '%02x'\n", byte); switch (byte) { case 0x23: /* direct convention used, but decoded using inverse * convention (a parity error should also have occurred) */ /* fall-through */ - case 0x30: + case 0x03: /* inverse convention used, but decoded using direct * convention (a parity error should also have occurred) */ ip->convention_convert = !ip->convention_convert; @@ -732,7 +741,7 @@ static void atr_wait_tX_action(struct osmo_fsm_inst *fi, uint32_t event, void *d switch (event) { case ISO7816_E_RX_SINGLE: - byte = get_rx_byte_evt(fi->proc.parent, data); + byte = get_atr_rx_byte_evt(fi->proc.parent, data); LOGPFSML(fi, LOGL_DEBUG, "RX byte '%02x'\n", byte); atr_append_byte(fi, byte); switch (fi->state) { diff --git a/sysmoOCTSIM/cuart_driver_asf4_usart_async.c b/sysmoOCTSIM/cuart_driver_asf4_usart_async.c index 89cd734..e6d180c 100644 --- a/sysmoOCTSIM/cuart_driver_asf4_usart_async.c +++ b/sysmoOCTSIM/cuart_driver_asf4_usart_async.c @@ -159,6 +159,19 @@ static const double sercom_glck_freqs[] = {100E6 / CONF_GCLK_GEN_2_DIV, 100E6 / */ static const uint8_t SIM_peripheral_GCLK_ID[] = {SERCOM0_GCLK_ID_CORE, SERCOM1_GCLK_ID_CORE, SERCOM2_GCLK_ID_CORE, SERCOM3_GCLK_ID_CORE, SERCOM4_GCLK_ID_CORE, SERCOM5_GCLK_ID_CORE, SERCOM6_GCLK_ID_CORE, SERCOM7_GCLK_ID_CORE}; +/** inverted signalling as per 7816-3 : inverted bit, inverted bit order + */ +static void set_inverted_signalling(void* hw, bool on) { + + hri_sercomusart_clear_CTRLA_ENABLE_bit(hw); + + hri_sercomusart_write_CTRLA_DORD_bit(hw, !on); // inverted == msb first + hri_sercomusart_write_CTRLA_TXINV_bit(hw, on); + hri_sercomusart_write_CTRLA_RXINV_bit(hw, on); + hri_sercomusart_write_CTRLB_PMODE_bit(hw, on); // inverted == even parity + + hri_sercomusart_set_CTRLA_ENABLE_bit(hw); +} /** change baud rate of card slot * @param[in] slotnr slot number for which the baud rate should be set @@ -237,6 +250,7 @@ static bool slot_set_baudrate(struct card_uart *cuart, uint32_t baudrate) static bool slot_set_isorate(struct card_uart *cuart, enum ncn8025_sim_clkdiv clkdiv, uint16_t f, uint8_t d) { uint8_t slotnr = cuart->u.asf4.slot_nr; + struct usart_async_descriptor* slot = SIM_peripheral_descriptors[slotnr]; // input checks ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors)); @@ -275,6 +289,12 @@ static bool slot_set_isorate(struct card_uart *cuart, enum ncn8025_sim_clkdiv cl break; } + /* error interrupt off after reset due to possbile inverted atr and accompanying parity error + * this was automatically enabled during error callback registration */ + hri_sercomusart_write_INTEN_ERROR_bit(slot->device.hw, 0); + + set_inverted_signalling(slot->device.hw, false); + // set baud rate uint32_t baudrate = (freq * d) / f; // calculate actual baud rate return slot_set_baudrate(cuart, baudrate); // set baud rate @@ -435,6 +455,15 @@ static int asf4_usart_ctrl(struct card_uart *cuart, enum card_uart_ctl ctl, int ncn8025_get(cuart->u.asf4.slot_nr, &settings); return 20e6 / ncn8025_div_val[settings.clkdiv]; break; + case CUART_CTL_ERROR_AND_INV: + set_inverted_signalling(sercom, arg); + + /* clear pending errors that happened while the interrupt was off (ATR) and enable it*/ + hri_sercomusart_clear_interrupt_ERROR_bit(sercom); + hri_sercomusart_clear_STATUS_reg(sercom, 0xff); + volatile uint8_t dummy = hri_sercomusart_read_RXERRCNT_reg(sercom); + hri_sercomusart_set_INTEN_ERROR_bit(sercom); + break; default: return 0; } -- cgit v1.2.3