From f910171deda0933e506cf3ffc216ee8daa418c24 Mon Sep 17 00:00:00 2001 From: Tom Date: Tue, 16 Aug 2011 15:41:46 +0200 Subject: corrected spelling mistake and added 2 new papers for gsm specs --- Src/osmoconbb/src/target/firmware/calypso/sim.c | 740 ++++++++++++++++++++++++ 1 file changed, 740 insertions(+) create mode 100755 Src/osmoconbb/src/target/firmware/calypso/sim.c (limited to 'Src/osmoconbb/src/target/firmware/calypso/sim.c') diff --git a/Src/osmoconbb/src/target/firmware/calypso/sim.c b/Src/osmoconbb/src/target/firmware/calypso/sim.c new file mode 100755 index 0000000..a539cf8 --- /dev/null +++ b/Src/osmoconbb/src/target/firmware/calypso/sim.c @@ -0,0 +1,740 @@ +/* Driver for Simcard Controller inside TI Calypso/Iota */ + +/* (C) 2010 by Philipp Fabian Benedikt Maier + * + * All Rights Reserved + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include + +#include +#include +#include +#include +#include + +static int sim_rx_character_count = 0; /* How many bytes have been received by calypso_sim_receive() */ +static int sim_tx_character_count = 0; /* How many bytes have been transmitted by calypso_sim_transmit() */ +static int sim_tx_character_length = 0; /* How many bytes have to be transmitted by calypso_sim_transmit() */ +static uint8_t *rx_buffer = 0; /* RX-Buffer that is issued by calypso_sim_receive() */ +static uint8_t *tx_buffer = 0; /* TX-Buffer that is issued by calypso_sim_transmit() */ +volatile static int rxDoneFlag = 0; /* Used for rx synchronization instead of a semaphore in calypso_sim_receive() */ +volatile static int txDoneFlag = 0; /* Used for rx synchronization instead of a semaphore in calypso_sim_transmit() */ + +/* Display Register dump */ +void calypso_sim_regdump(void) +{ +#if (SIM_DEBUG == 1) + unsigned int regVal; + + + puts("\n\n\n"); + puts("====================== CALYPSO SIM REGISTER DUMP =====================\n"); + puts("Reg_sim_cmd register (R/W) - FFFE:0000\n"); + + + regVal = readw(REG_SIM_CMD); + printf(" |-REG_SIM_CMD = %04x\n", readw(REG_SIM_CMD)); + + if(regVal & REG_SIM_CMD_CMDCARDRST) + puts(" | |-REG_SIM_CMD_CMDCARDRST = 1 ==> SIM card reset sequence enabled.\n"); + else + puts(" | |-REG_SIM_CMD_CMDCARDRST = 0 ==> SIM card reset sequence disabled.\n"); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + if(regVal & REG_SIM_CMD_CMDIFRST) + puts(" | |-REG_SIM_CMD_CMDIFRST = 1\n"); + else + puts(" | |-REG_SIM_CMD_CMDIFRST = 0\n"); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + if(regVal & REG_SIM_CMD_CMDSTOP) + puts(" | |-REG_SIM_CMD_CMDSTOP = 1\n"); + else + puts(" | |-REG_SIM_CMD_CMDSTOP = 0\n"); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + if(regVal & REG_SIM_CMD_CMDSTART) + puts(" | |-REG_SIM_CMD_CMDSTART = 1 ==> SIM card start procedure active.\n"); + else + puts(" | |-REG_SIM_CMD_CMDSTART = 0\n"); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + if(regVal & REG_SIM_CMD_CMDSTART) + puts(" | |-REG_SIM_CMD_MODULE_CLK_EN = 1 ==> Clock of the module enabled.\n"); + else + puts(" | |-REG_SIM_CMD_MODULE_CLK_EN = 0 ==> Clock of the module disabled.\n"); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + regVal = readw(REG_SIM_STAT); + printf(" |-REG_SIM_STAT = %04x\n", regVal); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + if(regVal & REG_SIM_STAT_STATNOCARD) + puts(" | |-REG_SIM_STAT_STATNOCARD = 1 ==> No card!\n"); + else + puts(" | |-REG_SIM_STAT_STATNOCARD = 0 ==> Card detected!\n"); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + if(regVal & REG_SIM_STAT_STATTXPAR) + puts(" | |-REG_SIM_STAT_STATTXPAR = 1 ==> Parity ok!\n"); + else + puts(" | |-REG_SIM_STAT_STATTXPAR = 0 ==> Parity error!\n"); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + if(regVal & REG_SIM_STAT_STATFIFOFULL) + puts(" | |-REG_SIM_STAT_STATFIFOFULL = 1 ==> Fifo full!\n"); + else + puts(" | |-REG_SIM_STAT_STATFIFOFULL = 0\n"); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + if(regVal & REG_SIM_STAT_STATFIFOEMPTY) + puts(" | |-REG_SIM_STAT_STATFIFOEMPTY = 1 ==> Fifo empty!\n"); + else + puts(" | |-REG_SIM_STAT_STATFIFOEMPTY = 0\n"); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + regVal = readw(REG_SIM_CONF1); + printf(" |-REG_SIM_CONF1 = %04x\n", regVal); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + if(regVal & REG_SIM_CONF1_CONFCHKPAR) + puts(" | |-REG_SIM_CONF1_CONFCHKPAR = 1 ==> Parity check on reception enabled.\n"); + else + puts(" | |-REG_SIM_CONF1_CONFCHKPAR = 0 ==> Parity check on reception disabled.\n"); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + if(regVal & REG_SIM_CONF1_CONFCODCONV) + puts(" | |-REG_SIM_CONF1_CONFCODCONV = 1 ==> Coding convention is inverse.\n"); + else + puts(" | |-REG_SIM_CONF1_CONFCODCONV = 0 ==> Coding convention is direct (normal).\n"); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + if(regVal & REG_SIM_CONF1_CONFTXRX) + puts(" | |-REG_SIM_CONF1_CONFTXRX = 1 ==> SIO line direction is in transmit mode.\n"); + else + puts(" | |-REG_SIM_CONF1_CONFTXRX = 0 ==> SIO line direction is in receive mode.\n"); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + if(regVal & REG_SIM_CONF1_CONFSCLKEN) + puts(" | |-REG_SIM_CONF1_CONFSCLKEN = 1 ==> SIM clock in normal mode.\n"); + else + puts(" | |-REG_SIM_CONF1_CONFSCLKEN = 0 ==> SIM clock in standby mode.\n"); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + if(regVal & REG_SIM_CONF1_reserved) + puts(" | |-REG_SIM_CONF1_reserved = 1 ==> ETU period is 4*1/Fsclk.\n"); + else + puts(" | |-REG_SIM_CONF1_reserved = 0 ==> ETU period is CONFETUPERIOD.\n"); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + if(regVal & REG_SIM_CONF1_CONFSCLKDIV) + puts(" | |-REG_SIM_CONF1_CONFSCLKDIV = 1 ==> SIM clock frequency is 13/8 Mhz.\n"); + else + puts(" | |-REG_SIM_CONF1_CONFSCLKDIV = 0 ==> SIM clock frequency is 13/4 Mhz.\n"); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + if(regVal & REG_SIM_CONF1_CONFSCLKLEV) + puts(" | |-REG_SIM_CONF1_CONFSCLKLEV = 1 ==> SIM clock idle level is high.\n"); + else + puts(" | |-REG_SIM_CONF1_CONFSCLKLEV = 0 ==> SIM clock idle level is low.\n"); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + if(regVal & REG_SIM_CONF1_CONFETUPERIOD) + puts(" | |-REG_SIM_CONF1_CONFETUPERIOD = 1 ==> ETU period is 512/8*1/Fsclk.\n"); + else + puts(" | |-REG_SIM_CONF1_CONFETUPERIOD = 0 ==> ETU period is 372/8*1/Fsclk.\n"); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + if(regVal & REG_SIM_CONF1_CONFBYPASS) + puts(" | |-REG_SIM_CONF1_CONFBYPASS = 1 ==> Hardware timers and start and stop sequences are bypassed.\n"); + else + puts(" | |-REG_SIM_CONF1_CONFBYPASS = 0 ==> Hardware timers and start and stop sequences are normal.\n"); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + if(regVal & REG_SIM_CONF1_CONFSVCCLEV) + puts(" | |-REG_SIM_CONF1_CONFSVCCLEV = 1 ==> SVCC Level is high (Only valid when CONFBYPASS = 1).\n"); + else + puts(" | |-REG_SIM_CONF1_CONFSVCCLEV = 0 ==> SVCC Level is low (Only valid when CONFBYPASS = 1).\n"); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + if(regVal & REG_SIM_CONF1_CONFSRSTLEV) + puts(" | |-REG_SIM_CONF1_CONFSRSTLEV = 1 ==> SRST Level is high (Only valid when CONFBYPASS = 1).\n"); + else + puts(" | |-REG_SIM_CONF1_CONFSRSTLEV = 0 ==> SRST Level is low (Only valid when CONFBYPASS = 1).\n"); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + printf(" | |-REG_SIM_CONF1_CONFTRIG = 0x%x (FIFO trigger level)\n",(regVal >> REG_SIM_CONF1_CONFTRIG) & REG_SIM_CONF1_CONFTRIG_MASK); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + if(regVal & REG_SIM_CONF1_CONFSIOLOW) + puts(" | |-REG_SIM_CONF1_CONFSIOLOW = 1 ==> I/O is forced to low.\n"); + else + puts(" | |-REG_SIM_CONF1_CONFSIOLOW = 0\n"); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + regVal = readw(REG_SIM_CONF2); + printf(" |-REG_SIM_CONF2 = %04x\n", regVal); + printf(" | |-REG_SIM_CONF2_CONFTFSIM = 0x%x (time delay for filtering of SIM_CD)\n",(regVal >> REG_SIM_CONF2_CONFTFSIM) & REG_SIM_CONF2_CONFTFSIM_MASK); + printf(" | |-REG_SIM_CONF2_CONFTDSIM = 0x%x (time delay for contact activation/deactivation)\n",(regVal >> REG_SIM_CONF2_CONFTDSIM) & REG_SIM_CONF2_CONFTDSIM_MASK); + printf(" | |-REG_SIM_CONF2_CONFWAITI = 0x%x (CONFWAITI overflow wait time between two received chars)\n",(regVal >> REG_SIM_CONF2_CONFWAITI) & REG_SIM_CONF2_CONFWAITI_MASK); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + regVal = readw(REG_SIM_IT); + printf(" |-REG_SIM_IT = %04x\n", regVal); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + if(regVal & REG_SIM_IT_SIM_NATR) + puts(" | |-REG_SIM_IT_SIM_NATR = 1 ==> No answer to reset!\n"); + else + puts(" | |-REG_SIM_IT_SIM_NATR = 0 ==> On read access to REG_SIM_IT.\n"); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + if(regVal & REG_SIM_IT_SIM_WT) + puts(" | |-REG_SIM_IT_SIM_WT = 1 ==> Character underflow!\n"); + else + puts(" | |-REG_SIM_IT_SIM_WT = 0 ==> On read access to REG_SIM_IT.\n"); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + if(regVal & REG_SIM_IT_SIM_OV) + puts(" | |-REG_SIM_IT_SIM_OV = 1 ==> Receive overflow!\n"); + else + puts(" | |-REG_SIM_IT_SIM_OV = 0 ==> On read access to REG_SIM_IT.\n"); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + if(regVal & REG_SIM_IT_SIM_TX) + puts(" | |-REG_SIM_IT_SIM_TX = 1 ==> Waiting for character to transmit...\n"); + else + { + puts(" | |-REG_SIM_IT_SIM_TX = 0 ==> On write access to REG_SIM_DTX or on switching\n"); + puts(" | | from transmit to receive mode (CONFTXRX bit)\n"); + } + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + if(regVal & REG_SIM_IT_SIM_RX) + puts(" | |-REG_SIM_IT_SIM_RX = 1 ==> Waiting characters to be read...\n"); + else + puts(" | |-REG_SIM_IT_SIM_RX = 0 ==> On read access to REG_SIM_DRX.\n"); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + regVal = readw(REG_SIM_DRX); + printf(" |-REG_SIM_DRX = %04x\n", regVal); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + printf(" | |-REG_SIM_DRX_SIM_DRX = 0x%x (next data byte in FIFO available for reading)\n",(regVal >> REG_SIM_DRX_SIM_DRX) & REG_SIM_DRX_SIM_DRX_MASK); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + if(regVal & REG_SIM_DRX_STATRXPAR) + puts(" | |-REG_SIM_DRX_STATRXPAR = 1 ==> Parity Ok.\n"); + else + puts(" | |-REG_SIM_DRX_STATRXPAR = 0 ==> Parity error!\n"); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + regVal = readw(REG_SIM_DTX); + printf(" |-REG_SIM_DTX = %02x (next data byte to be transmitted)\n", regVal); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + regVal = readw(REG_SIM_MASKIT); + printf(" |-REG_SIM_MASKIT = %04x\n", regVal); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + if(regVal & REG_SIM_MASKIT_MASK_SIM_NATR) + puts(" | |-REG_SIM_MASKIT_MASK_SIM_NATR = 1 ==> No-answer-to-reset interrupt is masked.\n"); + else + puts(" | |-REG_SIM_MASKIT_MASK_SIM_NATR = 0 ==> No-answer-to-reset interrupt is unmasked.\n"); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + if(regVal & REG_SIM_MASKIT_MASK_SIM_WT) + puts(" | |-REG_SIM_MASKIT_MASK_SIM_WT = 1 ==> Character wait-time overflow interrupt is masked.\n"); + else + puts(" | |-REG_SIM_MASKIT_MASK_SIM_WT = 0 ==> Character wait-time overflow interrupt is unmasked.\n"); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + if(regVal & REG_SIM_MASKIT_MASK_SIM_OV) + puts(" | |-REG_SIM_MASKIT_MASK_SIM_OV = 1 ==> Receive overflow interrupt is masked.\n"); + else + puts(" | |-REG_SIM_MASKIT_MASK_SIM_OV = 0 ==> Receive overflow interrupt is unmasked.\n"); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + if(regVal & REG_SIM_MASKIT_MASK_SIM_TX) + puts(" | |-REG_SIM_MASKIT_MASK_SIM_TX = 1 ==> Waiting characters to be transmit interrupt is masked.\n"); + else + puts(" | |-REG_SIM_MASKIT_MASK_SIM_TX = 0 ==> Waiting characters to be transmit interrupt is unmasked.\n"); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + if(regVal & REG_SIM_MASKIT_MASK_SIM_RX) + puts(" | |-REG_SIM_MASKIT_MASK_SIM_RX = 1 ==> Waiting characters to be read interrupt is masked.\n"); + else + puts(" | |-REG_SIM_MASKIT_MASK_SIM_RX = 0 ==> Waiting characters to be read interrupt is unmasked.\n"); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + if(regVal & REG_SIM_MASKIT_MASK_SIM_CD) + puts(" | |-REG_SIM_MASKIT_MASK_SIM_CD = 1 ==> SIM card insertion/extraction interrupt is masked.\n"); + else + puts(" | |-REG_SIM_MASKIT_MASK_SIM_CD = 0 ==> SIM card insertion/extraction interrupt is unmasked.\n"); + delay_ms(SIM_DEBUG_OUTPUTDELAY); + + regVal = REG_SIM_IT_CD; + printf(" |-REG_SIM_IT_CD = %04x\n", regVal); + if(regVal & REG_SIM_IT_CD_IT_CD) + puts(" |-REG_SIM_IT_CD_IT_CD = 1 ==> SIM card insertion/extraction interrupt is masked.\n"); + else + puts(" |-REG_SIM_IT_CD_IT_CD = 0 ==> SIM card insertion/extraction interrupt is unmasked.\n"); + delay_ms(SIM_DEBUG_OUTPUTDELAY); +#endif + return; +} + +/* Apply power to the simcard (use nullpointer to ignore atr) */ +int calypso_sim_powerup(uint8_t *atr) +{ + /* Enable level shifters and voltage regulator */ + twl3025_reg_write(VRPCSIM, VRPCSIM_SIMLEN | VRPCSIM_RSIMEN | VRPCSIM_SIMSEL); +#if (SIM_DEBUG == 1) + puts(" * Power enabled!\n"); +#endif + delay_ms(SIM_OPERATION_DELAY); + + /* Enable clock */ + writew(REG_SIM_CMD_MODULE_CLK_EN | REG_SIM_CMD_CMDSTART, REG_SIM_CMD); +#if (SIM_DEBUG == 1) + puts(" * Clock enabled!\n"); +#endif + delay_ms(SIM_OPERATION_DELAY); + + /* Release reset */ + writew(readw(REG_SIM_CONF1) | REG_SIM_CONF1_CONFBYPASS | REG_SIM_CONF1_CONFSRSTLEV | REG_SIM_CONF1_CONFSVCCLEV, REG_SIM_CONF1); +#if (SIM_DEBUG == 1) + puts(" * Reset released!\n"); +#endif + + /* Catch ATR */ + if(atr != 0) + return calypso_sim_receive(atr); + else + return 0; +} + + +/* Powerdown simcard */ +void calypso_sim_powerdown(void) +{ + writew(readw(REG_SIM_CONF1) & ~REG_SIM_CONF1_CONFBYPASS, REG_SIM_CONF1); +#if (SIM_DEBUG == 1) + puts(" * Reset pulled down!\n"); +#endif + delay_ms(SIM_OPERATION_DELAY); + + writew(REG_SIM_CMD_MODULE_CLK_EN | REG_SIM_CMD_CMDSTOP, REG_SIM_CMD); +#if (SIM_DEBUG == 1) + puts(" * Clock disabled!\n"); +#endif + delay_ms(SIM_OPERATION_DELAY); + + writew(0, REG_SIM_CMD); +#if (SIM_DEBUG == 1) + puts(" * Module disabled!\n"); +#endif + delay_ms(SIM_OPERATION_DELAY); + + /* Disable level shifters and voltage regulator */ + twl3025_reg_write(VRPCSIM, 0); +#if (SIM_DEBUG == 1) + puts(" * Power disabled!\n"); +#endif + delay_ms(SIM_OPERATION_DELAY); + + return; +} + +/* reset the simcard (see note 1) */ +int calypso_sim_reset(uint8_t *atr) +{ + + /* Pull reset down */ + writew(readw(REG_SIM_CONF1) & ~REG_SIM_CONF1_CONFSRSTLEV , REG_SIM_CONF1); +#if (SIM_DEBUG == 1) + puts(" * Reset pulled down!\n"); +#endif + + delay_ms(SIM_OPERATION_DELAY); + + /* Pull reset down */ + writew(readw(REG_SIM_CONF1) | REG_SIM_CONF1_CONFSRSTLEV , REG_SIM_CONF1); +#if (SIM_DEBUG == 1) + puts(" * Reset released!\n"); +#endif + + /* Catch ATR */ + if(atr != 0) + return calypso_sim_receive(atr); + else + return 0; +} + +/* Receive raw data through the sim interface */ +int calypso_sim_receive(uint8_t *data) +{ + /* Prepare buffers and flags */ + rx_buffer = data; + sim_rx_character_count = 0; + rxDoneFlag = 0; + + /* Switch I/O direction to input */ + writew(readw(REG_SIM_CONF1) & ~REG_SIM_CONF1_CONFTXRX, REG_SIM_CONF1); + + /* Unmask the interrupts that are needed to perform this action */ + writew(~(REG_SIM_MASKIT_MASK_SIM_RX | REG_SIM_MASKIT_MASK_SIM_WT), REG_SIM_MASKIT); + + /* Wait till rxDoneFlag is set */ + while(rxDoneFlag == 0); + + /* Disable all interrupt driven functions by masking all interrupts */ + writew(0xFF, REG_SIM_MASKIT); + + /* Hand back the number of bytes received */ + return sim_rx_character_count; + + return; +} + +/* Transmit raw data through the sim interface */ +int calypso_sim_transmit(uint8_t *data, int length) +{ + /* Prepare buffers and flags */ + tx_buffer = data; + sim_tx_character_count = 0; + txDoneFlag = 0; + sim_tx_character_length = length; + + /* Switch I/O direction to output */ + writew(readw(REG_SIM_CONF1) | REG_SIM_CONF1_CONFTXRX, REG_SIM_CONF1); + + /* Unmask the interrupts that are needed to perform this action */ + writew(~(REG_SIM_MASKIT_MASK_SIM_TX), REG_SIM_MASKIT); + + /* Transmit the first byte manually to start the interrupt cascade */ + writew(*tx_buffer,REG_SIM_DTX); + tx_buffer++; + sim_tx_character_count++; + + /* Wait till rxDoneFlag is set */ + while(txDoneFlag == 0); + + /* Disable all interrupt driven functions by masking all interrupts */ + writew(0xFF, REG_SIM_MASKIT); + + return 0; +} + + +/* IRQ-Handler for simcard interface */ +void sim_irq_handler(enum irq_nr irq) +{ + int regVal = readw(REG_SIM_IT); + + + /* Display interrupt information */ +#if (SIM_DEBUG == 1) + puts("SIM-ISR: Interrupt caught: "); +#endif + if(regVal & REG_SIM_IT_SIM_NATR) + { +#if (SIM_DEBUG == 1) + puts(" No answer to reset!\n"); +#endif + } + + /* Used by: calypso_sim_receive() to determine when the transmission is over */ + if(regVal & REG_SIM_IT_SIM_WT) + { +#if (SIM_DEBUG == 1) + puts(" Character underflow!\n"); +#endif + rxDoneFlag = 1; + } + + if(regVal & REG_SIM_IT_SIM_OV) + { +#if (SIM_DEBUG == 1) + puts(" Receive overflow!\n"); +#endif + } + + /* Used by: calypso_sim_transmit() to transmit the data */ + if(regVal & REG_SIM_IT_SIM_TX) + { +#if (SIM_DEBUG == 1) + puts(" Waiting for character to transmit...\n"); +#endif + if(sim_tx_character_count >= sim_tx_character_length) + txDoneFlag = 1; + else + { + writew(*tx_buffer,REG_SIM_DTX); + tx_buffer++; + sim_tx_character_count++; + } + } + + /* Used by: calypso_sim_receive() to receive the incoming data */ + if(regVal & REG_SIM_IT_SIM_RX) + { +#if (SIM_DEBUG == 1) + puts(" Waiting characters to be read...\n"); +#endif + /* 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 = (uint8_t) (readw(REG_SIM_DRX) & 0xFF); + rx_buffer++; + } +} + +/* Transceive T0 Apdu to sim acording to GSM 11.11 Page 34 */ +int calypso_sim_transceive(uint8_t cla, /* Class (in GSM context mostly 0xA0 */ + uint8_t ins, /* Instruction */ + uint8_t p1, /* First parameter */ + uint8_t p2, /* Second parameter */ + uint8_t p3le, /* Length of the data that should be transceived */ + uint8_t *data, /* Data payload */ + uint8_t *status, /* Status word (2 byte array, see note 1) */ + uint8_t mode) /* Mode of operation: 1=GET, 0=PUT */ + + /* Note 1: You can use a null-pointer (0) if you are not interested in + the status word */ +{ + uint8_t transmissionBuffer[256]; + uint8_t numberOfReceivedBytes; + +#if (SIM_DEBUG == 1) + printf("SIM-T0: Transceiving APDU-Header: (%02x %02x %02x %02x %02x)\n",cla,ins,p1,p2,p3le); +#endif + + /* Transmit APDU header */ + memset(transmissionBuffer,0,sizeof(transmissionBuffer)); + transmissionBuffer[0] = cla; + transmissionBuffer[1] = ins; + transmissionBuffer[2] = p1; + transmissionBuffer[3] = p2; + transmissionBuffer[4] = p3le; + calypso_sim_transmit(transmissionBuffer,5); + + /* Case 1: No input, No Output */ + if(p3le == 0) + { +#if (SIM_DEBUG == 1) + puts("SIM-T0: Case 1: No input, No Output (See also GSM 11.11 Page 34)\n"); +#endif + numberOfReceivedBytes = calypso_sim_receive(transmissionBuffer); + + if(numberOfReceivedBytes == 2) + { +#if (SIM_DEBUG == 1) + printf("SIM-T0: Status-word received: %02x %02x\n", transmissionBuffer[0], transmissionBuffer[1]); +#endif + /* Hand back status word */ + if(status != 0) + { + status[0] = transmissionBuffer[0]; + status[1] = transmissionBuffer[1]; + } + + return 0; + } + else + { +#if (SIM_DEBUG == 1) + puts("SIM-T0: T0 Protocol error -- aborting!\n"); +#endif + return -1; + } + } + + /* Case 2: No input / Output of known length */ + else if(mode == SIM_APDU_PUT) + { +#if (SIM_DEBUG == 1) + puts("SIM-T0: Case 2: No input / Output of known length (See also GSM 11.11 Page 34)\n"); +#endif + + numberOfReceivedBytes = calypso_sim_receive(transmissionBuffer); + + /* Error situation: The card has aborted, sends no data but a status word */ + if(numberOfReceivedBytes == 2) + { +#if (SIM_DEBUG == 1) + printf("SIM-T0: Status-word received (ERROR): %02x %02x\n", transmissionBuffer[0], transmissionBuffer[1]); +#endif + /* Hand back status word */ + if(status != 0) + { + status[0] = transmissionBuffer[0]; + status[1] = transmissionBuffer[1]; + } + + return 0; + } + /* Acknoledge byte received */ + else if(numberOfReceivedBytes == 1) + { +#if (SIM_DEBUG == 1) + printf("SIM-T0: ACK received: %02x\n", transmissionBuffer[0]); +#endif + /* Check if ACK is valid */ + if(transmissionBuffer[0] != ins) + { +#if (SIM_DEBUG == 1) + puts("SIM-T0: T0 Protocol error: Invalid ACK byte -- aborting!\n"); +#endif + return -1; + } + + /* Transmit body */ + calypso_sim_transmit(data,p3le); + + /* Receive status word */ + numberOfReceivedBytes = calypso_sim_receive(transmissionBuffer); + + /* Check status word */ + if(numberOfReceivedBytes == 2) + { +#if (SIM_DEBUG == 1) + printf("SIM-T0: Status-word received: %02x %02x\n", transmissionBuffer[0], transmissionBuffer[1]); +#endif + + /* Hand back status word */ + if(status != 0) + { + status[0] = transmissionBuffer[0]; + status[1] = transmissionBuffer[1]; + } + + return 0; + } + else + { +#if (SIM_DEBUG == 1) + puts("SIM-T0: T0 Protocol error: Missing or invalid status word -- aborting!\n"); +#endif + return -1; + } + } + else + { +#if (SIM_DEBUG == 1) + puts("SIM-T0: T0 Protocol error: Missing ACK byte -- aborting!\n"); +#endif + return -1; + } + } + + /* Case 4: Input / No output */ + else if(mode == SIM_APDU_GET) + { +#if (SIM_DEBUG == 1) + puts("SIM-T0: Case 4: Input / No output (See also GSM 11.11 Page 34)\n"); +#endif + + numberOfReceivedBytes = calypso_sim_receive(data); + + /* Error situation: The card has aborted, sends no data but a status word */ + if(numberOfReceivedBytes == 2) + { + +#if (SIM_DEBUG == 1) + printf("SIM-T0: Status-word received (ERROR): %02x %02x\n", data[0], data[1]); +#endif + /* Hand back status word */ + if(status != 0) + { + status[0] = data[0]; + status[1] = data[1]; + } + + return 0; + } + + /* Data correctly received */ + else if(numberOfReceivedBytes == p3le + 1 + 2) + { +#if (SIM_DEBUG == 1) + printf("SIM-T0: ACK received: %02x\n", data[0]); +#endif + /* Check if ACK is valid */ + if(data[0] != ins) + { +#if (SIM_DEBUG == 1) + puts("SIM-T0: T0 Protocol error: Invalid ACK byte -- aborting!\n"); +#endif + return -1; + } + +#if (SIM_DEBUG == 1) + printf("SIM-T0: Status-word received: %02x %02x\n", data[p3le + 1], data[p3le + 2]); +#endif + /* Hand back status word */ + if(status != 0) + { + status[0] = data[p3le + 1]; + status[1] = data[p3le + 2]; + } + + /* Move data one position left to cut away the ACK-Byte */ + memcpy(data,data+1,p3le); + + return 0; + } + else + { +#if (SIM_DEBUG == 1) + puts("SIM-T0: T0 Protocol error: Incorrect or missing answer -- aborting!\n"); +#endif + return -1; + } + } + + /* Should not happen, if it happens then the programmer has submitted invalid parameters! */ + else + { +#if (SIM_DEBUG == 1) + puts("SIM-T0: T0 Protocol error: Invalid case (program bug!) -- aborting!\n"); +#endif + } + + /* Note: The other cases are not implemented because they are already covered + by the CASE 1,2 and 4. */ + + return 0; +} + + +/* Initialize simcard interface */ +void calypso_sim_init(void) +{ + /* Register IRQ handler and turn interrupts on */ +#if (SIM_DEBUG == 1) + puts("SIM: Registering interrupt handler for simcard-interface\n"); +#endif + irq_register_handler(IRQ_SIMCARD, &sim_irq_handler); + irq_config(IRQ_SIMCARD, 0, 0, 0xff); + irq_enable(IRQ_SIMCARD); +} + -- cgit v1.2.3-55-g7522