summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuca Melette <luca@srlabs.de>2013-12-20 19:20:03 +0100
committerLuca Melette <luca@srlabs.de>2013-12-20 19:20:03 +0100
commit07f29edcc6502d36986b3cb94c6eb404d5424b45 (patch)
treec4a9c205b487c47c31fd34b8ccc54b1f09b380ea
parente0fbb2a75798c50bc9eb67158d3451b8e3a749d6 (diff)
Applying SIM handler fixesluca/catcher
-rw-r--r--src/target/firmware/calypso/sim.c84
-rw-r--r--src/target/firmware/layer1/l23_api.c6
2 files changed, 56 insertions, 34 deletions
diff --git a/src/target/firmware/calypso/sim.c b/src/target/firmware/calypso/sim.c
index 752628f..39cb56c 100644
--- a/src/target/firmware/calypso/sim.c
+++ b/src/target/firmware/calypso/sim.c
@@ -43,6 +43,7 @@
/* Class that contains the following instructions */
#define SIM_GET_RESPONSE 0xC0
/* Get the response of a command from the card */
+#define SIM_FETCH 0x12
#define SIM_READ_BINARY 0xB0 /* Read file in binary mode */
#define SIM_READ_RECORD 0xB2 /* Read record in binary mode */
@@ -347,7 +348,7 @@ void calypso_sim_regdump(void)
/* Receive raw data through the sim interface */
int calypso_sim_receive(uint8_t *data, uint8_t len)
{
- printd("Triggering SIM reception\n");
+ printd("Triggering SIM reception, len = %d bytes\n", len);
/* Prepare buffers and flags */
rx_buffer = data;
@@ -396,12 +397,12 @@ void sim_irq_handler(enum irq_nr irq)
{
int regVal = readw(REG_SIM_IT);
-
/* Display interrupt information */
printd("SIM-ISR: ");
if(regVal & REG_SIM_IT_SIM_NATR) {
- printd(" No answer to reset!\n");
+ puts("SIM: No answer to reset!\n");
+ rxDoneFlag = 1;
}
/* Used by: calypso_sim_receive() to determine when the transmission
@@ -444,31 +445,36 @@ void sim_irq_handler(enum irq_nr irq)
/* Used by: calypso_sim_receive() to receive the incoming data */
if(regVal & REG_SIM_IT_SIM_RX) {
- uint8_t ch = (uint8_t) (readw(REG_SIM_DRX) & 0xFF);
-
- /* ignore NULL procedure byte */
- if(ch == 0x60 && sim_ignore_waiting_char) {
- printd(" 0x60 received...\n");
- return;
- }
-
- printd(" Waiting for read (%02X)...\n", ch);
-
- /* Increment character count - this is what
- * calypso_sim_receive() hands back
- */
- sim_rx_character_count++;
+ /* read while FIFO is not empty otherwise we can get FIFO full
+ if we wait for REG_SIM_IT_SIM_RX for each char */
+ while ((readw(REG_SIM_STAT) & REG_SIM_STAT_STATFIFOEMPTY) == 0) {
+ uint8_t ch = (uint8_t) (readw(REG_SIM_DRX) & 0xFF);
+
+ /* ignore NULL procedure byte */
+ if(ch == 0x60 && sim_ignore_waiting_char) {
+ printd(" 0x60 received...\n");
+ return;
+ }
- /* Read byte from rx-fifo and write it to the issued buffer */
- *rx_buffer = ch;
- rx_buffer++;
+ printd(" Waiting for read (%02X)...\n", ch);
- /* to maximise SIM access speed, stop waiting after
- all the expected characters have been received. */
- if (sim_rx_max_character_count
- && sim_rx_character_count >= sim_rx_max_character_count) {
- printd(" Max characters received!\n");
- rxDoneFlag = 1;
+ /* Increment character count - this is what
+ * calypso_sim_receive() hands back
+ */
+ sim_rx_character_count++;
+
+ /* Read byte from rx-fifo and write it to the issued buffer */
+ *rx_buffer = ch;
+ rx_buffer++;
+
+ /* to maximise SIM access speed, stop waiting after
+ all the expected characters have been received. */
+ if (sim_rx_max_character_count
+ && sim_rx_character_count >= sim_rx_max_character_count) {
+ printd(" Max characters received!\n");
+ rxDoneFlag = 1;
+ break;
+ }
}
}
}
@@ -477,7 +483,7 @@ void sim_irq_handler(enum irq_nr irq)
void sim_apdu(uint16_t len, uint8_t *data)
{
if (sim_state != SIM_STATE_IDLE) {
- puts("Sim reader currently busy...\n");
+ puts("SIM: reader currently busy...\n");
return;
}
memcpy(sim_data, data, len);
@@ -500,7 +506,7 @@ void sim_handler(void)
/* check if instructions expects a response */
if (/* GET RESPONSE needs SIM_APDU_GET */
(sim_len == 5 && sim_data[0] == SIM_CLASS &&
- sim_data[1] == SIM_GET_RESPONSE && sim_data[2] == 0x00 &&
+ (sim_data[1] == SIM_GET_RESPONSE || sim_data[1] == SIM_FETCH) && sim_data[2] == 0x00 &&
sim_data[3] == 0x00) ||
/* READ BINARY/RECORD needs SIM_APDU_GET */
(sim_len >= 5 && sim_data[0] == SIM_CLASS &&
@@ -659,6 +665,10 @@ void calypso_sim_init(void)
/* Apply power to the simcard (use nullpointer to ignore atr) */
int calypso_sim_powerup(uint8_t *atr)
{
+ /* put state machine back into idle */
+ sim_len = 0;
+ sim_state = SIM_STATE_IDLE;
+
/* Enable level shifters and voltage regulator */
#if 1 // 2.9V
twl3025_reg_write(VRPCSIM, VRPCSIM_SIMLEN | VRPCSIM_RSIMEN
@@ -687,14 +697,19 @@ int calypso_sim_powerup(uint8_t *atr)
;
}
- return 0;
+ /* Disable all interrupt driven functions */
+ writew(0xFF, REG_SIM_MASKIT);
+
+ return sim_rx_character_count;
}
/* Powerdown simcard */
void calypso_sim_powerdown(void)
{
- writew(readw(REG_SIM_CONF1) & ~REG_SIM_CONF1_CONFBYPASS, REG_SIM_CONF1);
+ // according to the specification CONFTXRX | CONFSCLKEN is a default reset value of conf1 register
+ // if CONFSVCCLEV or CONFSRSTLEV remains enabled even without CONFBYPASS, SIM is never properly powered down
+ writew(REG_SIM_CONF1_CONFTXRX | REG_SIM_CONF1_CONFSCLKEN, REG_SIM_CONF1);
printd(" * Reset pulled down!\n");
delay_ms(SIM_OPERATION_DELAY);
@@ -725,6 +740,10 @@ int calypso_sim_reset(uint8_t *atr)
delay_ms(SIM_OPERATION_DELAY);
+ /* put state machine back into idle */
+ sim_len = 0;
+ sim_state = SIM_STATE_IDLE;
+
/* Pull reset down */
writew(readw(REG_SIM_CONF1) | REG_SIM_CONF1_CONFSRSTLEV, REG_SIM_CONF1);
printd(" * Reset released!\n");
@@ -736,6 +755,9 @@ int calypso_sim_reset(uint8_t *atr)
;
}
- return 0;
+ /* Disable all interrupt driven functions */
+ writew(0xFF, REG_SIM_MASKIT);
+
+ return sim_rx_character_count;
}
diff --git a/src/target/firmware/layer1/l23_api.c b/src/target/firmware/layer1/l23_api.c
index ae39e63..ac5c4fd 100644
--- a/src/target/firmware/layer1/l23_api.c
+++ b/src/target/firmware/layer1/l23_api.c
@@ -19,8 +19,8 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
-
-#define DEBUG
+/* Uncomment to debug */
+/* #define DEBUG */
#include <stdint.h>
#include <stdio.h>
@@ -571,7 +571,7 @@ static void l1ctl_sim_req(struct msgb *msg)
uint16_t len = msg->len - sizeof(struct l1ctl_hdr);
uint8_t *data = msg->data + sizeof(struct l1ctl_hdr);
-#if 1 /* for debugging only */
+#ifdef DEBUG /* for debugging only */
{
int i;
printf("SIM Request (%u): ", len);