<p>Hoernchen has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-ccid-firmware/+/21117">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">asf4 uart: properly handle uart errors<br><br>Uart will now lead to a (temporary) deactivation of the uart as well as<br>the deactivatin of the card + a a proper ccid response to notify the<br>host if the slot was busy.<br><br>Change-Id: Ia0efef03829b68d2b4f25899bb933b14fb9e0bd1<br>---<br>M ccid_common/ccid_slot_fsm.c<br>M ccid_common/cuart.h<br>M ccid_common/iso7816_fsm.c<br>M sysmoOCTSIM/cuart_driver_asf4_usart_async.c<br>4 files changed, 97 insertions(+), 21 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-ccid-firmware refs/changes/17/21117/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/ccid_common/ccid_slot_fsm.c b/ccid_common/ccid_slot_fsm.c</span><br><span>index 4cf75bc..8dccfa5 100644</span><br><span>--- a/ccid_common/ccid_slot_fsm.c</span><br><span>+++ b/ccid_common/ccid_slot_fsm.c</span><br><span>@@ -147,12 +147,18 @@</span><br><span> msgb_free(msg);</span><br><span> /* continues in iso_fsm_clot_user_cb once ATR is received */</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static void iso_fsm_clot_user_cb(struct osmo_fsm_inst *fi, int event, int cause, void *data)</span><br><span> {</span><br><span> struct iso_fsm_slot *ss = iso7816_fsm_get_user_priv(fi);</span><br><span> struct ccid_slot *cs = ss->cs;</span><br><span> </span><br><span> switch (event) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* special case: not handled as a normal callback below, in case slot was busy the fsm will</span><br><span style="color: hsl(120, 100%, 40%);">+ * additionally emit a proper error event handled below to notify the host */</span><br><span style="color: hsl(120, 100%, 40%);">+ case ISO7816_E_HW_ERR_IND:</span><br><span style="color: hsl(120, 100%, 40%);">+ card_uart_ctrl(ss->cuart, CUART_CTL_NO_RXTX, true);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span> case ISO7816_E_ATR_DONE_IND:</span><br><span> case ISO7816_E_ATR_ERR_IND:</span><br><span> case ISO7816_E_TPDU_DONE_IND:</span><br><span>@@ -219,10 +225,14 @@</span><br><span> break;</span><br><span> case ISO7816_E_ATR_ERR_IND:</span><br><span> tpdu = data;</span><br><span style="color: hsl(0, 100%, 40%);">- LOGPCS(cs, LOGL_DEBUG, "%s(event=%d, data=%s)\n", __func__, event,</span><br><span style="color: hsl(0, 100%, 40%);">- msgb_hexdump(tpdu));</span><br><span style="color: hsl(0, 100%, 40%);">- resp = ccid_gen_data_block(cs, ss->seq, CCID_CMD_STATUS_FAILED, CCID_ERR_ICC_MUTE,</span><br><span style="color: hsl(0, 100%, 40%);">- msgb_data(tpdu), msgb_length(tpdu));</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPCS(cs, LOGL_DEBUG, "%s(event=%d, data=%s)\n", __func__, event, msgb_hexdump(tpdu));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* perform deactivation */</span><br><span style="color: hsl(120, 100%, 40%);">+ card_uart_ctrl(ss->cuart, CUART_CTL_RST, true);</span><br><span style="color: hsl(120, 100%, 40%);">+ card_uart_ctrl(ss->cuart, CUART_CTL_POWER_5V0, false);</span><br><span style="color: hsl(120, 100%, 40%);">+ cs->icc_powered = false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ resp = ccid_gen_data_block(cs, ss->seq, CCID_CMD_STATUS_FAILED, CCID_ERR_ICC_MUTE, msgb_data(tpdu), msgb_length(tpdu));</span><br><span> ccid_slot_send_unbusy(cs, resp);</span><br><span> cs->event = 0;</span><br><span> break;</span><br><span>@@ -237,8 +247,13 @@</span><br><span> break;</span><br><span> case ISO7816_E_TPDU_FAILED_IND:</span><br><span> tpdu = data;</span><br><span style="color: hsl(0, 100%, 40%);">- LOGPCS(cs, LOGL_DEBUG, "%s(event=%d, data=%s)\n", __func__, event,</span><br><span style="color: hsl(0, 100%, 40%);">- msgb_hexdump(tpdu));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* perform deactivation */</span><br><span style="color: hsl(120, 100%, 40%);">+ card_uart_ctrl(ss->cuart, CUART_CTL_RST, true);</span><br><span style="color: hsl(120, 100%, 40%);">+ card_uart_ctrl(ss->cuart, CUART_CTL_POWER_5V0, false);</span><br><span style="color: hsl(120, 100%, 40%);">+ cs->icc_powered = false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGPCS(cs, LOGL_DEBUG, "%s(event=%d, data=%s)\n", __func__, event, msgb_hexdump(tpdu));</span><br><span> /* FIXME: other error causes than card removal?*/</span><br><span> resp = ccid_gen_data_block(cs, ss->seq, CCID_CMD_STATUS_FAILED, CCID_ERR_ICC_MUTE, msgb_l2(tpdu), 0);</span><br><span> ccid_slot_send_unbusy(cs, resp);</span><br><span>diff --git a/ccid_common/cuart.h b/ccid_common/cuart.h</span><br><span>index c0a3a52..c8573c5 100644</span><br><span>--- a/ccid_common/cuart.h</span><br><span>+++ b/ccid_common/cuart.h</span><br><span>@@ -36,6 +36,7 @@</span><br><span> CUART_E_RX_TIMEOUT,</span><br><span> /* an entire block of data was written, as instructed in prior card_uart_tx() call */</span><br><span> CUART_E_TX_COMPLETE,</span><br><span style="color: hsl(120, 100%, 40%);">+ CUART_E_HW_ERROR, /* might be uart parity or mystery error, might be something else */</span><br><span> };</span><br><span> </span><br><span> extern const struct value_string card_uart_event_vals[];</span><br><span>diff --git a/ccid_common/iso7816_fsm.c b/ccid_common/iso7816_fsm.c</span><br><span>index 8e113b0..7207245 100644</span><br><span>--- a/ccid_common/iso7816_fsm.c</span><br><span>+++ b/ccid_common/iso7816_fsm.c</span><br><span>@@ -276,6 +276,9 @@</span><br><span> case CUART_E_TX_COMPLETE:</span><br><span> osmo_fsm_inst_dispatch(fi, ISO7816_E_TX_COMPL, data);</span><br><span> break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case CUART_E_HW_ERROR:</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fsm_inst_dispatch(fi, ISO7816_E_HW_ERR_IND, data);</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span> }</span><br><span> }</span><br><span> </span><br><span>@@ -361,7 +364,7 @@</span><br><span> struct iso7816_3_priv *ip = get_iso7816_3_priv(fi);</span><br><span> OSMO_ASSERT(fi->fsm == &iso7816_3_fsm);</span><br><span> card_uart_ctrl(ip->uart, CUART_CTL_RX_TIMER_HINT, 0);</span><br><span style="color: hsl(0, 100%, 40%);">- card_uart_ctrl(ip->uart, CUART_CTL_NO_RXTX, true);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* reset the TPDU state machine */</span><br><span> osmo_fsm_inst_dispatch(ip->tpdu_fi, ISO7816_E_TPDU_CLEAR_REQ, NULL);</span><br><span> }</span><br><span>@@ -424,6 +427,9 @@</span><br><span> </span><br><span> switch (event) {</span><br><span> case ISO7816_E_HW_ERR_IND:</span><br><span style="color: hsl(120, 100%, 40%);">+ /* deactivates uart, then continues with the callbacks below for proper error reporting */</span><br><span style="color: hsl(120, 100%, 40%);">+ ip->user_cb(fi, ISO7816_E_HW_ERR_IND, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* no break */</span><br><span> case ISO7816_E_CARD_REMOVAL:</span><br><span> /* FIXME: power off? */</span><br><span> if(fi->state == ISO7816_S_WAIT_ATR || fi->state == ISO7816_S_IN_ATR)</span><br><span>diff --git a/sysmoOCTSIM/cuart_driver_asf4_usart_async.c b/sysmoOCTSIM/cuart_driver_asf4_usart_async.c</span><br><span>index 64ec9f2..42c2110 100644</span><br><span>--- a/sysmoOCTSIM/cuart_driver_asf4_usart_async.c</span><br><span>+++ b/sysmoOCTSIM/cuart_driver_asf4_usart_async.c</span><br><span>@@ -56,11 +56,10 @@</span><br><span> #include <hpl_usart_sync.h></span><br><span> </span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static void _SIM_error_cb(const struct usart_async_descriptor *const descr){</span><br><span style="color: hsl(0, 100%, 40%);">- volatile uint32_t status = hri_sercomusart_read_STATUS_reg(descr->device.hw);</span><br><span style="color: hsl(0, 100%, 40%);">- volatile uint32_t data = hri_sercomusart_read_DATA_reg(descr->device.hw);</span><br><span style="color: hsl(0, 100%, 40%);">- volatile uint32_t errrs = hri_sercomusart_read_RXERRCNT_reg(descr->device.hw);</span><br><span style="color: hsl(0, 100%, 40%);">- OSMO_ASSERT(0 == 1)</span><br><span style="color: hsl(120, 100%, 40%);">+static void _SIM_error_cb(const struct usart_async_descriptor *const io_descr, uint8_t slot_nr) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct card_uart *cuart = cuart4slot_nr(slot_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(cuart);</span><br><span style="color: hsl(120, 100%, 40%);">+ card_uart_notification(cuart, CUART_E_HW_ERROR, 0);</span><br><span> }</span><br><span> </span><br><span> /* the below ugli-ness is required as the usart_async_descriptor doesn't have</span><br><span>@@ -139,6 +138,44 @@</span><br><span> SIM4_tx_cb, SIM5_tx_cb, SIM6_tx_cb, SIM7_tx_cb,</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static void SIM0_error_cb(const struct usart_async_descriptor *const io_descr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ _SIM_error_cb(io_descr, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+static void SIM1_error_cb(const struct usart_async_descriptor *const io_descr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ _SIM_error_cb(io_descr, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+static void SIM2_error_cb(const struct usart_async_descriptor *const io_descr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ _SIM_error_cb(io_descr, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+static void SIM3_error_cb(const struct usart_async_descriptor *const io_descr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ _SIM_error_cb(io_descr, 3);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+static void SIM4_error_cb(const struct usart_async_descriptor *const io_descr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ _SIM_error_cb(io_descr, 4);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+static void SIM5_error_cb(const struct usart_async_descriptor *const io_descr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ _SIM_error_cb(io_descr, 5);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+static void SIM6_error_cb(const struct usart_async_descriptor *const io_descr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ _SIM_error_cb(io_descr, 6);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+static void SIM7_error_cb(const struct usart_async_descriptor *const io_descr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ _SIM_error_cb(io_descr, 7);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+static usart_cb_t SIM_error_cb[8] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ SIM0_error_cb, SIM1_error_cb, SIM2_error_cb, SIM3_error_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+ SIM4_error_cb, SIM5_error_cb, SIM6_error_cb, SIM7_error_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #include <math.h></span><br><span> #include "atmel_start.h"</span><br><span> #include "atmel_start_pins.h"</span><br><span>@@ -182,9 +219,14 @@</span><br><span> static bool slot_set_baudrate(struct card_uart *cuart, uint32_t baudrate)</span><br><span> {</span><br><span> uint8_t slotnr = cuart->u.asf4.slot_nr;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(120, 100%, 40%);">+ struct usart_async_descriptor* slot = SIM_peripheral_descriptors[slotnr];</span><br><span style="color: hsl(120, 100%, 40%);">+ Sercom *sercom = cuart->u.asf4.usa_pd->device.hw;</span><br><span> ASSERT(slotnr < ARRAY_SIZE(SIM_peripheral_descriptors));</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ if (NULL == slot) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> // calculate the error corresponding to the clock sources</span><br><span> uint16_t bauds[ARRAY_SIZE(sercom_glck_freqs)];</span><br><span> double errors[ARRAY_SIZE(sercom_glck_freqs)];</span><br><span>@@ -218,11 +260,6 @@</span><br><span> return false;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- // set clock and baud rate</span><br><span style="color: hsl(0, 100%, 40%);">- struct usart_async_descriptor* slot = SIM_peripheral_descriptors[slotnr]; // get slot</span><br><span style="color: hsl(0, 100%, 40%);">- if (NULL == slot) {</span><br><span style="color: hsl(0, 100%, 40%);">- return false;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span> </span><br><span> // update cached values</span><br><span> cuart->u.asf4.current_baudrate = baudrate;</span><br><span>@@ -231,7 +268,7 @@</span><br><span> 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]);</span><br><span> </span><br><span> /* only wait if the uart is enabled.... */</span><br><span style="color: hsl(0, 100%, 40%);">- if (hri_sercomusart_get_CTRLA_reg(slot->device.hw, SERCOM_USART_CTRLA_ENABLE)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (hri_sercomusart_get_CTRLA_reg(sercom, SERCOM_USART_CTRLA_ENABLE)) {</span><br><span> while (!usart_async_is_tx_empty(slot)); // wait for transmission to complete (WARNING no timeout)</span><br><span> usart_async_disable(slot); // disable SERCOM peripheral</span><br><span> }</span><br><span>@@ -241,6 +278,17 @@</span><br><span> // it does not seem we need to completely disable the peripheral using hri_mclk_clear_APBDMASK_SERCOMn_bit</span><br><span> 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</span><br><span> usart_async_set_baud_rate(slot, bauds[best]); // set the new baud rate</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* clear pending errors that happened while</span><br><span style="color: hsl(120, 100%, 40%);">+ * - the interrupt was off (inverse ATR? -> parity error)</span><br><span style="color: hsl(120, 100%, 40%);">+ * -- OR --</span><br><span style="color: hsl(120, 100%, 40%);">+ * - the uart was disabled due to a hw error</span><br><span style="color: hsl(120, 100%, 40%);">+ * and enable it*/</span><br><span style="color: hsl(120, 100%, 40%);">+ hri_sercomusart_clear_interrupt_ERROR_bit(sercom);</span><br><span style="color: hsl(120, 100%, 40%);">+ hri_sercomusart_clear_STATUS_reg(sercom, 0xff);</span><br><span style="color: hsl(120, 100%, 40%);">+ volatile uint8_t dummy = hri_sercomusart_read_RXERRCNT_reg(sercom);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ usart_async_flush_rx_buffer(cuart->u.asf4.usa_pd);</span><br><span> usart_async_enable(slot); // re-enable SERCOM peripheral</span><br><span> </span><br><span> return true;</span><br><span>@@ -330,7 +378,7 @@</span><br><span> </span><br><span> usart_async_register_callback(usa_pd, USART_ASYNC_RXC_CB, SIM_rx_cb[slot_nr]);</span><br><span> usart_async_register_callback(usa_pd, USART_ASYNC_TXC_CB, SIM_tx_cb[slot_nr]);</span><br><span style="color: hsl(0, 100%, 40%);">- usart_async_register_callback(usa_pd, USART_ASYNC_ERROR_CB, _SIM_error_cb);</span><br><span style="color: hsl(120, 100%, 40%);">+ usart_async_register_callback(usa_pd, USART_ASYNC_ERROR_CB, SIM_error_cb[slot_nr]);</span><br><span> usart_async_enable(usa_pd);</span><br><span> </span><br><span> // set USART baud rate to match the interface (f = 2.5 MHz) and card default settings (Fd = 372, Dd = 1)</span><br><span>@@ -385,7 +433,13 @@</span><br><span> </span><br><span> switch (ctl) {</span><br><span> case CUART_CTL_NO_RXTX:</span><br><span style="color: hsl(0, 100%, 40%);">- /* no op */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* immediately disables the uart, useful for hw errors (parity, colllision, ...)</span><br><span style="color: hsl(120, 100%, 40%);">+ * uart is automatically re-enabled during slot_set_isorate which also clears the errors</span><br><span style="color: hsl(120, 100%, 40%);">+ * when resetting the slot which happens automatically during error callback handling or powerup</span><br><span style="color: hsl(120, 100%, 40%);">+ * so the uart usually does not stay disabled for a long time */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (arg)</span><br><span style="color: hsl(120, 100%, 40%);">+ _usart_async_disable(&cuart->u.asf4.usa_pd->device);</span><br><span> break;</span><br><span> case CUART_CTL_RX:</span><br><span> if (arg){</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-ccid-firmware/+/21117">change 21117</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/osmo-ccid-firmware/+/21117"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: osmo-ccid-firmware </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Ia0efef03829b68d2b4f25899bb933b14fb9e0bd1 </div>
<div style="display:none"> Gerrit-Change-Number: 21117 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Hoernchen <ewild@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>