mirror of
https://gitea.osmocom.org/sim-card/simtrace2.git
synced 2026-03-17 13:48:32 +03:00
Structure build system to build for multiple boards/apps/environments
This commit is contained in:
998
firmware/libcommon/source/card_emu.c
Normal file
998
firmware/libcommon/source/card_emu.c
Normal file
@@ -0,0 +1,998 @@
|
||||
/* ISO7816-3 state machine for the card side */
|
||||
/* (C) 2010-2015 by Harald Welte <hwelte@hmw-consulting.de>
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
//#define TRACE_LEVEL 6
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "trace.h"
|
||||
#include "iso7816_fidi.h"
|
||||
#include "tc_etu.h"
|
||||
#include "card_emu.h"
|
||||
#include "req_ctx.h"
|
||||
#include "cardemu_prot.h"
|
||||
#include "osmocom/core/linuxlist.h"
|
||||
|
||||
|
||||
#define NUM_SLOTS 2
|
||||
|
||||
#define ISO7816_3_INIT_WTIME 9600
|
||||
#define ISO7816_3_DEFAULT_WI 10
|
||||
#define ISO7816_3_ATR_LEN_MAX (1+32) /* TS plus 32 chars */
|
||||
|
||||
#define ISO7816_3_PB_NULL 0x60
|
||||
|
||||
enum iso7816_3_card_state {
|
||||
ISO_S_WAIT_POWER, /* waiting for power being applied */
|
||||
ISO_S_WAIT_CLK, /* waiting for clock being applied */
|
||||
ISO_S_WAIT_RST, /* waiting for reset being released */
|
||||
ISO_S_WAIT_ATR, /* waiting for start of ATR */
|
||||
ISO_S_IN_ATR, /* transmitting ATR to reader */
|
||||
ISO_S_IN_PTS, /* transmitting ATR to reader */
|
||||
ISO_S_WAIT_TPDU, /* waiting for data from reader */
|
||||
ISO_S_IN_TPDU, /* inside a TPDU */
|
||||
};
|
||||
|
||||
/* detailed sub-states of ISO_S_IN_PTS */
|
||||
enum pts_state {
|
||||
PTS_S_WAIT_REQ_PTSS,
|
||||
PTS_S_WAIT_REQ_PTS0,
|
||||
PTS_S_WAIT_REQ_PTS1,
|
||||
PTS_S_WAIT_REQ_PTS2,
|
||||
PTS_S_WAIT_REQ_PTS3,
|
||||
PTS_S_WAIT_REQ_PCK,
|
||||
PTS_S_WAIT_RESP_PTSS = PTS_S_WAIT_REQ_PTSS | 0x10,
|
||||
PTS_S_WAIT_RESP_PTS0 = PTS_S_WAIT_REQ_PTS0 | 0x10,
|
||||
PTS_S_WAIT_RESP_PTS1 = PTS_S_WAIT_REQ_PTS1 | 0x10,
|
||||
PTS_S_WAIT_RESP_PTS2 = PTS_S_WAIT_REQ_PTS2 | 0x10,
|
||||
PTS_S_WAIT_RESP_PTS3 = PTS_S_WAIT_REQ_PTS3 | 0x10,
|
||||
PTS_S_WAIT_RESP_PCK = PTS_S_WAIT_REQ_PCK | 0x10,
|
||||
};
|
||||
|
||||
#define _PTSS 0
|
||||
#define _PTS0 1
|
||||
#define _PTS1 2
|
||||
#define _PTS2 3
|
||||
#define _PTS3 4
|
||||
#define _PCK 5
|
||||
|
||||
/* T-PDU state machine states */
|
||||
enum tpdu_state {
|
||||
TPDU_S_WAIT_CLA, /* waiting for CLA byte from reader */
|
||||
TPDU_S_WAIT_INS, /* waiting for INS byte from reader */
|
||||
TPDU_S_WAIT_P1, /* waiting for P1 byte from reader */
|
||||
TPDU_S_WAIT_P2, /* waiting for P2 byte from reader */
|
||||
TPDU_S_WAIT_P3, /* waiting for P3 byte from reader */
|
||||
TPDU_S_WAIT_PB, /* waiting for Tx of procedure byte */
|
||||
TPDU_S_WAIT_RX, /* waiitng for more data from reader */
|
||||
TPDU_S_WAIT_TX, /* waiting for more data to reader */
|
||||
};
|
||||
|
||||
#define _CLA 0
|
||||
#define _INS 1
|
||||
#define _P1 2
|
||||
#define _P2 3
|
||||
#define _P3 4
|
||||
|
||||
struct card_handle {
|
||||
uint32_t num;
|
||||
|
||||
enum iso7816_3_card_state state;
|
||||
|
||||
/* signal levels */
|
||||
uint8_t vcc_active; /* 1 = on, 0 = off */
|
||||
uint8_t in_reset; /* 1 = RST low, 0 = RST high */
|
||||
uint8_t clocked; /* 1 = active, 0 = inactive */
|
||||
|
||||
/* timing parameters, from PTS */
|
||||
uint8_t fi;
|
||||
uint8_t di;
|
||||
uint8_t wi;
|
||||
|
||||
uint8_t tc_chan; /* TC channel number */
|
||||
uint8_t uart_chan; /* UART channel */
|
||||
|
||||
uint32_t waiting_time; /* in clocks */
|
||||
|
||||
/* ATR state machine */
|
||||
struct {
|
||||
uint8_t idx;
|
||||
uint8_t len;
|
||||
//uint8_t hist_len;
|
||||
//uint8_t last_td;
|
||||
uint8_t atr[ISO7816_3_ATR_LEN_MAX];
|
||||
} atr;
|
||||
|
||||
/* PPS / PTS support */
|
||||
struct {
|
||||
enum pts_state state;
|
||||
uint8_t req[6]; /* request bytes */
|
||||
uint8_t resp[6]; /* response bytes */
|
||||
} pts;
|
||||
|
||||
/* TPDU */
|
||||
struct {
|
||||
enum tpdu_state state;
|
||||
uint8_t hdr[5]; /* CLA INS P1 P2 P3 */
|
||||
} tpdu;
|
||||
|
||||
struct req_ctx *uart_rx_ctx; /* UART RX -> USB TX */
|
||||
struct req_ctx *uart_tx_ctx; /* USB RX -> UART TX */
|
||||
|
||||
struct llist_head usb_tx_queue;
|
||||
struct llist_head uart_tx_queue;
|
||||
|
||||
struct {
|
||||
uint32_t tx_bytes;
|
||||
uint32_t rx_bytes;
|
||||
uint32_t pps;
|
||||
} stats;
|
||||
};
|
||||
|
||||
struct llist_head *card_emu_get_usb_tx_queue(struct card_handle *ch)
|
||||
{
|
||||
return &ch->usb_tx_queue;
|
||||
}
|
||||
|
||||
struct llist_head *card_emu_get_uart_tx_queue(struct card_handle *ch)
|
||||
{
|
||||
return &ch->uart_tx_queue;
|
||||
}
|
||||
|
||||
static void set_tpdu_state(struct card_handle *ch, enum tpdu_state new_ts);
|
||||
static void set_pts_state(struct card_handle *ch, enum pts_state new_ptss);
|
||||
|
||||
static void flush_rx_buffer(struct card_handle *ch)
|
||||
{
|
||||
struct req_ctx *rctx;
|
||||
struct cardemu_usb_msg_rx_data *rd;
|
||||
|
||||
rctx = ch->uart_rx_ctx;
|
||||
if (!rctx)
|
||||
return;
|
||||
|
||||
ch->uart_rx_ctx = NULL;
|
||||
|
||||
/* store length of data payload fild in header */
|
||||
rd = (struct cardemu_usb_msg_rx_data *) rctx->data;
|
||||
rd->data_len = rctx->idx;
|
||||
rd->hdr.msg_len = sizeof(*rd) + rd->data_len;
|
||||
|
||||
req_ctx_set_state(rctx, RCTX_S_USB_TX_PENDING);
|
||||
/* no need for irqsafe operation, as the usb_tx_queue is
|
||||
* processed only by the main loop context */
|
||||
llist_add_tail(&rctx->list, &ch->usb_tx_queue);
|
||||
}
|
||||
|
||||
/* convert a non-contiguous PTS request/responsei into a contiguous
|
||||
* buffer, returning the number of bytes used in the buffer */
|
||||
static int serialize_pts(uint8_t *out, const uint8_t *in)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
out[i++] = in[_PTSS];
|
||||
out[i++] = in[_PTS0];
|
||||
if (in[_PTS0] & (1 << 4))
|
||||
out[i++] = in[_PTS1];
|
||||
if (in[_PTS0] & (1 << 5))
|
||||
out[i++] = in[_PTS2];
|
||||
if (in[_PTS0] & (1 << 6))
|
||||
out[i++] = in[_PTS3];
|
||||
out[i++] = in[_PCK];
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static uint8_t csum_pts(const uint8_t *in)
|
||||
{
|
||||
uint8_t out[6];
|
||||
int len = serialize_pts(out, in);
|
||||
uint8_t csum = 0;
|
||||
int i;
|
||||
|
||||
/* we don't include the PCK byte in the checksumming process */
|
||||
len -= 1;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
csum = csum ^ out[i];
|
||||
|
||||
return csum;
|
||||
}
|
||||
|
||||
static void flush_pts(struct card_handle *ch)
|
||||
{
|
||||
struct req_ctx *rctx;
|
||||
struct cardemu_usb_msg_pts_info *ptsi;
|
||||
|
||||
rctx = req_ctx_find_get(0, RCTX_S_FREE, RCTX_S_UART_RX_BUSY);
|
||||
if (!rctx)
|
||||
return;
|
||||
|
||||
ptsi = (struct cardemu_usb_msg_pts_info *) rctx->data;
|
||||
ptsi->hdr.msg_type = CEMU_USB_MSGT_DO_PTS;
|
||||
ptsi->hdr.msg_len = sizeof(*ptsi);
|
||||
ptsi->pts_len = serialize_pts(ptsi->req, ch->pts.req);
|
||||
serialize_pts(ptsi->resp, ch->pts.resp);
|
||||
|
||||
req_ctx_set_state(rctx, RCTX_S_USB_TX_PENDING);
|
||||
/* no need for irqsafe operation, as the usb_tx_queue is
|
||||
* processed only by the main loop context */
|
||||
llist_add_tail(&rctx->list, &ch->usb_tx_queue);
|
||||
}
|
||||
|
||||
static void emu_update_fidi(struct card_handle *ch)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = compute_fidi_ratio(ch->fi, ch->di);
|
||||
if (rc > 0 && rc < 0x400) {
|
||||
TRACE_INFO("%u: computed Fi(%u) Di(%u) ratio: %d\r\n",
|
||||
ch->num, ch->fi, ch->di, rc);
|
||||
/* make sure UART uses new F/D ratio */
|
||||
card_emu_uart_update_fidi(ch->uart_chan, rc);
|
||||
/* notify ETU timer about this */
|
||||
tc_etu_set_etu(ch->tc_chan, rc);
|
||||
} else
|
||||
TRACE_INFO("%u: computed FiDi ration %d unsupported\r\n",
|
||||
ch->num, rc);
|
||||
}
|
||||
|
||||
/* Update the ISO 7816-3 TPDU receiver state */
|
||||
static void card_set_state(struct card_handle *ch,
|
||||
enum iso7816_3_card_state new_state)
|
||||
{
|
||||
if (ch->state == new_state)
|
||||
return;
|
||||
|
||||
TRACE_DEBUG("%u: 7816 card state %u -> %u\r\n", ch->num,
|
||||
ch->state, new_state);
|
||||
ch->state = new_state;
|
||||
|
||||
switch (new_state) {
|
||||
case ISO_S_WAIT_POWER:
|
||||
case ISO_S_WAIT_CLK:
|
||||
case ISO_S_WAIT_RST:
|
||||
/* disable Rx and Tx of UART */
|
||||
card_emu_uart_enable(ch->uart_chan, 0);
|
||||
break;
|
||||
case ISO_S_WAIT_ATR:
|
||||
set_pts_state(ch, PTS_S_WAIT_REQ_PTSS);
|
||||
/* Reset to initial Fi / Di ratio */
|
||||
ch->fi = 1;
|
||||
ch->di = 1;
|
||||
emu_update_fidi(ch);
|
||||
/* initialize todefault WI, this will be overwritten if we
|
||||
* receive TC2, and it will be programmed into hardware after
|
||||
* ATR is finished */
|
||||
ch->wi = ISO7816_3_DEFAULT_WI;
|
||||
/* update waiting time to initial waiting time */
|
||||
ch->waiting_time = ISO7816_3_INIT_WTIME;
|
||||
tc_etu_set_wtime(ch->tc_chan, ch->waiting_time);
|
||||
/* Set ATR sub-state to initial state */
|
||||
ch->atr.idx = 0;
|
||||
//set_atr_state(ch, ATR_S_WAIT_TS);
|
||||
/* Notice that we are just coming out of reset */
|
||||
//ch->sh.flags |= SIMTRACE_FLAG_ATR;
|
||||
card_emu_uart_enable(ch->uart_chan, ENABLE_TX);
|
||||
break;
|
||||
break;
|
||||
case ISO_S_WAIT_TPDU:
|
||||
/* enable the receiver, disable transmitter */
|
||||
set_tpdu_state(ch, TPDU_S_WAIT_CLA);
|
||||
card_emu_uart_enable(ch->uart_chan, ENABLE_RX);
|
||||
break;
|
||||
case ISO_S_IN_ATR:
|
||||
case ISO_S_IN_PTS:
|
||||
case ISO_S_IN_TPDU:
|
||||
/* do nothing */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* PTS / PPS handling
|
||||
**********************************************************************/
|
||||
|
||||
/* Update the ATR sub-state */
|
||||
static void set_pts_state(struct card_handle *ch, enum pts_state new_ptss)
|
||||
{
|
||||
TRACE_DEBUG("%u: 7816 PTS state %u -> %u\r\n",
|
||||
ch->num, ch->pts.state, new_ptss);
|
||||
ch->pts.state = new_ptss;
|
||||
}
|
||||
|
||||
/* Determine the next PTS state */
|
||||
static enum pts_state next_pts_state(struct card_handle *ch)
|
||||
{
|
||||
uint8_t is_resp = ch->pts.state & 0x10;
|
||||
uint8_t sstate = ch->pts.state & 0x0f;
|
||||
uint8_t *pts_ptr;
|
||||
|
||||
if (!is_resp)
|
||||
pts_ptr = ch->pts.req;
|
||||
else
|
||||
pts_ptr = ch->pts.resp;
|
||||
|
||||
switch (sstate) {
|
||||
case PTS_S_WAIT_REQ_PTSS:
|
||||
goto from_ptss;
|
||||
case PTS_S_WAIT_REQ_PTS0:
|
||||
goto from_pts0;
|
||||
case PTS_S_WAIT_REQ_PTS1:
|
||||
goto from_pts1;
|
||||
case PTS_S_WAIT_REQ_PTS2:
|
||||
goto from_pts2;
|
||||
case PTS_S_WAIT_REQ_PTS3:
|
||||
goto from_pts3;
|
||||
}
|
||||
|
||||
if (ch->pts.state == PTS_S_WAIT_REQ_PCK)
|
||||
return PTS_S_WAIT_RESP_PTSS;
|
||||
|
||||
from_ptss:
|
||||
return PTS_S_WAIT_REQ_PTS0 | is_resp;
|
||||
from_pts0:
|
||||
if (pts_ptr[_PTS0] & (1 << 4))
|
||||
return PTS_S_WAIT_REQ_PTS1 | is_resp;
|
||||
from_pts1:
|
||||
if (pts_ptr[_PTS0] & (1 << 5))
|
||||
return PTS_S_WAIT_REQ_PTS2 | is_resp;
|
||||
from_pts2:
|
||||
if (pts_ptr[_PTS0] & (1 << 6))
|
||||
return PTS_S_WAIT_REQ_PTS3 | is_resp;
|
||||
from_pts3:
|
||||
return PTS_S_WAIT_REQ_PCK | is_resp;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
process_byte_pts(struct card_handle *ch, uint8_t byte)
|
||||
{
|
||||
switch (ch->pts.state) {
|
||||
case PTS_S_WAIT_REQ_PTSS:
|
||||
ch->pts.req[_PTSS] = byte;
|
||||
break;
|
||||
case PTS_S_WAIT_REQ_PTS0:
|
||||
ch->pts.req[_PTS0] = byte;
|
||||
break;
|
||||
case PTS_S_WAIT_REQ_PTS1:
|
||||
ch->pts.req[_PTS1] = byte;
|
||||
break;
|
||||
case PTS_S_WAIT_REQ_PTS2:
|
||||
ch->pts.req[_PTS2] = byte;
|
||||
break;
|
||||
case PTS_S_WAIT_REQ_PTS3:
|
||||
ch->pts.req[_PTS3] = byte;
|
||||
break;
|
||||
case PTS_S_WAIT_REQ_PCK:
|
||||
ch->pts.req[_PCK] = byte;
|
||||
if (ch->pts.req[_PCK] != csum_pts(ch->pts.req)) {
|
||||
TRACE_ERROR("%u: Error in PTS Checksum!\r\n",
|
||||
ch->num);
|
||||
/* Wait for the next TPDU */
|
||||
set_pts_state(ch, PTS_S_WAIT_REQ_PTSS);
|
||||
return ISO_S_WAIT_TPDU;
|
||||
}
|
||||
/* FIXME: check if proposal matches capabilities in ATR */
|
||||
memcpy(ch->pts.resp, ch->pts.req, sizeof(ch->pts.resp));
|
||||
break;
|
||||
default:
|
||||
TRACE_ERROR("%u: process_byte_pts() in invalid state %u\r\n",
|
||||
ch->num, ch->pts.state);
|
||||
break;
|
||||
}
|
||||
/* calculate the next state and set it */
|
||||
set_pts_state(ch, next_pts_state(ch));
|
||||
|
||||
if (ch->pts.state == PTS_S_WAIT_RESP_PTSS) {
|
||||
flush_pts(ch);
|
||||
/* activate UART TX to transmit PTS response */
|
||||
card_emu_uart_enable(ch->uart_chan, ENABLE_TX);
|
||||
/* don't fall-through to the 'return ISO_S_IN_PTS'
|
||||
* below, rather keep ISO7816 state as-is, it will be
|
||||
* further updated by the tx-completion handler */
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ISO_S_IN_PTS;
|
||||
}
|
||||
|
||||
/* return a single byte to be transmitted to the reader */
|
||||
static int tx_byte_pts(struct card_handle *ch)
|
||||
{
|
||||
uint8_t byte;
|
||||
|
||||
/* 1: Determine the next transmit byte */
|
||||
switch (ch->pts.state) {
|
||||
case PTS_S_WAIT_RESP_PTSS:
|
||||
byte = ch->pts.resp[_PTSS];
|
||||
break;
|
||||
case PTS_S_WAIT_RESP_PTS0:
|
||||
byte = ch->pts.resp[_PTS0];
|
||||
break;
|
||||
case PTS_S_WAIT_RESP_PTS1:
|
||||
byte = ch->pts.resp[_PTS1];
|
||||
/* This must be TA1 */
|
||||
ch->fi = byte >> 4;
|
||||
ch->di = byte & 0xf;
|
||||
TRACE_DEBUG("%u: found Fi=%u Di=%u\r\n", ch->num,
|
||||
ch->fi, ch->di);
|
||||
break;
|
||||
case PTS_S_WAIT_RESP_PTS2:
|
||||
byte = ch->pts.resp[_PTS2];
|
||||
break;
|
||||
case PTS_S_WAIT_RESP_PTS3:
|
||||
byte = ch->pts.resp[_PTS3];
|
||||
break;
|
||||
case PTS_S_WAIT_RESP_PCK:
|
||||
byte = ch->pts.resp[_PCK];
|
||||
break;
|
||||
default:
|
||||
TRACE_ERROR("%u: get_byte_pts() in invalid state %u\r\n",
|
||||
ch->num, ch->pts.state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 2: Transmit the byte */
|
||||
card_emu_uart_tx(ch->uart_chan, byte);
|
||||
|
||||
/* 3: Update the state */
|
||||
|
||||
switch (ch->pts.state) {
|
||||
case PTS_S_WAIT_RESP_PCK:
|
||||
card_emu_uart_wait_tx_idle(ch->uart_chan);
|
||||
/* update baud rate generator with Fi/Di */
|
||||
emu_update_fidi(ch);
|
||||
/* Wait for the next TPDU */
|
||||
card_set_state(ch, ISO_S_WAIT_TPDU);
|
||||
set_pts_state(ch, PTS_S_WAIT_REQ_PTSS);
|
||||
break;
|
||||
default:
|
||||
/* calculate the next state and set it */
|
||||
set_pts_state(ch, next_pts_state(ch));
|
||||
break;
|
||||
}
|
||||
|
||||
/* return number of bytes transmitted */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* TPDU handling
|
||||
**********************************************************************/
|
||||
|
||||
|
||||
/* compute number of data bytes according to Chapter 10.3.2 of 7816-3 */
|
||||
static unsigned int t0_num_data_bytes(uint8_t p3, int reader_to_card)
|
||||
{
|
||||
if (reader_to_card) {
|
||||
return p3;
|
||||
} else {
|
||||
if (p3 == 0)
|
||||
return 256;
|
||||
else
|
||||
return p3;
|
||||
}
|
||||
}
|
||||
|
||||
/* add a just-received TPDU byte (from reader) to USB buffer */
|
||||
static void add_tpdu_byte(struct card_handle *ch, uint8_t byte)
|
||||
{
|
||||
struct req_ctx *rctx;
|
||||
struct cardemu_usb_msg_rx_data *rd;
|
||||
unsigned int num_data_bytes = t0_num_data_bytes(ch->tpdu.hdr[_P3], 0);
|
||||
|
||||
/* ensure we have a buffer */
|
||||
if (!ch->uart_rx_ctx) {
|
||||
rctx = ch->uart_rx_ctx = req_ctx_find_get(0, RCTX_S_FREE, RCTX_S_UART_RX_BUSY);
|
||||
if (!ch->uart_rx_ctx) {
|
||||
TRACE_ERROR("%u: Received UART byte but ENOMEM\r\n",
|
||||
ch->num);
|
||||
return;
|
||||
}
|
||||
rd = (struct cardemu_usb_msg_rx_data *) ch->uart_rx_ctx->data;
|
||||
cardemu_hdr_set(&rd->hdr, CEMU_USB_MSGT_DO_RX_DATA);
|
||||
rctx->tot_len = sizeof(*rd);
|
||||
rctx->idx = 0;
|
||||
} else
|
||||
rctx = ch->uart_rx_ctx;
|
||||
|
||||
rd = (struct cardemu_usb_msg_rx_data *) rctx->data;
|
||||
|
||||
rd->data[rctx->idx++] = byte;
|
||||
rctx->tot_len++;
|
||||
|
||||
/* check if the buffer is full. If so, send it */
|
||||
if (rctx->tot_len >= sizeof(*rd) + num_data_bytes) {
|
||||
rd->flags |= CEMU_DATA_F_FINAL;
|
||||
flush_rx_buffer(ch);
|
||||
/* We need to transmit the SW now, */
|
||||
set_tpdu_state(ch, TPDU_S_WAIT_TX);
|
||||
} else if (rctx->tot_len >= rctx->size)
|
||||
flush_rx_buffer(ch);
|
||||
}
|
||||
|
||||
static void set_tpdu_state(struct card_handle *ch, enum tpdu_state new_ts)
|
||||
{
|
||||
if (ch->tpdu.state == new_ts)
|
||||
return;
|
||||
|
||||
TRACE_DEBUG("%u: 7816 TPDU state %u -> %u\r\n", ch->num,
|
||||
ch->tpdu.state, new_ts);
|
||||
|
||||
ch->tpdu.state = new_ts;
|
||||
|
||||
switch (new_ts) {
|
||||
case TPDU_S_WAIT_CLA:
|
||||
case TPDU_S_WAIT_RX:
|
||||
card_emu_uart_enable(ch->uart_chan, ENABLE_RX);
|
||||
break;
|
||||
case TPDU_S_WAIT_PB:
|
||||
/* we just completed the TPDU header from reader to card
|
||||
* and now need to disable the receiver, enable the
|
||||
* transmitter and transmit the procedure byte */
|
||||
card_emu_uart_enable(ch->uart_chan, ENABLE_TX);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static enum tpdu_state next_tpdu_state(struct card_handle *ch)
|
||||
{
|
||||
switch (ch->tpdu.state) {
|
||||
case TPDU_S_WAIT_CLA:
|
||||
return TPDU_S_WAIT_INS;
|
||||
case TPDU_S_WAIT_INS:
|
||||
return TPDU_S_WAIT_P1;
|
||||
case TPDU_S_WAIT_P1:
|
||||
return TPDU_S_WAIT_P2;
|
||||
case TPDU_S_WAIT_P2:
|
||||
return TPDU_S_WAIT_P3;
|
||||
case TPDU_S_WAIT_P3:
|
||||
return TPDU_S_WAIT_PB;
|
||||
/* simply stay in Rx or Tx by default */
|
||||
case TPDU_S_WAIT_PB:
|
||||
return TPDU_S_WAIT_PB;
|
||||
case TPDU_S_WAIT_RX:
|
||||
return TPDU_S_WAIT_RX;
|
||||
case TPDU_S_WAIT_TX:
|
||||
return TPDU_S_WAIT_TX;
|
||||
}
|
||||
/* we should never reach here */
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void send_tpdu_header(struct card_handle *ch)
|
||||
{
|
||||
struct req_ctx *rctx;
|
||||
struct cardemu_usb_msg_rx_data *rd;
|
||||
|
||||
TRACE_INFO("%u: %s: %02x %02x %02x %02x %02x\r\n",
|
||||
ch->num, __func__,
|
||||
ch->tpdu.hdr[0], ch->tpdu.hdr[1],
|
||||
ch->tpdu.hdr[2], ch->tpdu.hdr[3],
|
||||
ch->tpdu.hdr[4]);
|
||||
|
||||
/* if we already/still have a context, send it off */
|
||||
if (ch->uart_rx_ctx) {
|
||||
TRACE_DEBUG("%u: have old buffer\r\n", ch->num);
|
||||
if (ch->uart_rx_ctx->idx) {
|
||||
TRACE_DEBUG("%u: flushing old buffer\r\n", ch->num);
|
||||
flush_rx_buffer(ch);
|
||||
}
|
||||
} else {
|
||||
TRACE_DEBUG("%u: allocating new buffer\r\n", ch->num);
|
||||
/* ensure we have a new buffer */
|
||||
ch->uart_rx_ctx = req_ctx_find_get(0, RCTX_S_FREE, RCTX_S_UART_RX_BUSY);
|
||||
if (!ch->uart_rx_ctx) {
|
||||
TRACE_ERROR("%u: %s: ENOMEM\r\n", ch->num, __func__);
|
||||
return;
|
||||
}
|
||||
}
|
||||
rctx = ch->uart_rx_ctx;
|
||||
rd = (struct cardemu_usb_msg_rx_data *) rctx->data;
|
||||
|
||||
/* initializ header */
|
||||
cardemu_hdr_set(&rd->hdr, CEMU_USB_MSGT_DO_RX_DATA);
|
||||
rd->flags = CEMU_DATA_F_TPDU_HDR;
|
||||
rctx->tot_len = sizeof(*rd) + sizeof(ch->tpdu.hdr);
|
||||
rctx->idx = sizeof(ch->tpdu.hdr);
|
||||
|
||||
/* copy TPDU header to data field */
|
||||
memcpy(rd->data, ch->tpdu.hdr, sizeof(ch->tpdu.hdr));
|
||||
/* rd->data_len is set in flush_rx_buffer() */
|
||||
|
||||
flush_rx_buffer(ch);
|
||||
}
|
||||
|
||||
static enum iso7816_3_card_state
|
||||
process_byte_tpdu(struct card_handle *ch, uint8_t byte)
|
||||
{
|
||||
switch (ch->tpdu.state) {
|
||||
case TPDU_S_WAIT_CLA:
|
||||
ch->tpdu.hdr[_CLA] = byte;
|
||||
set_tpdu_state(ch, next_tpdu_state(ch));
|
||||
break;
|
||||
case TPDU_S_WAIT_INS:
|
||||
ch->tpdu.hdr[_INS] = byte;
|
||||
set_tpdu_state(ch, next_tpdu_state(ch));
|
||||
break;
|
||||
case TPDU_S_WAIT_P1:
|
||||
ch->tpdu.hdr[_P1] = byte;
|
||||
set_tpdu_state(ch, next_tpdu_state(ch));
|
||||
break;
|
||||
case TPDU_S_WAIT_P2:
|
||||
ch->tpdu.hdr[_P2] = byte;
|
||||
set_tpdu_state(ch, next_tpdu_state(ch));
|
||||
break;
|
||||
case TPDU_S_WAIT_P3:
|
||||
ch->tpdu.hdr[_P3] = byte;
|
||||
set_tpdu_state(ch, next_tpdu_state(ch));
|
||||
/* FIXME: start timer to transmit further 0x60 */
|
||||
/* send the TPDU header as part of a procedure byte
|
||||
* request to the USB host */
|
||||
send_tpdu_header(ch);
|
||||
break;
|
||||
case TPDU_S_WAIT_RX:
|
||||
add_tpdu_byte(ch, byte);
|
||||
break;
|
||||
default:
|
||||
TRACE_ERROR("%u: process_byte_tpdu() in invalid state %u\r\n",
|
||||
ch->num, ch->tpdu.state);
|
||||
}
|
||||
|
||||
/* ensure we stay in TPDU ISO state */
|
||||
return ISO_S_IN_TPDU;
|
||||
}
|
||||
|
||||
/* tx a single byte to be transmitted to the reader */
|
||||
static int tx_byte_tpdu(struct card_handle *ch)
|
||||
{
|
||||
struct req_ctx *rctx;
|
||||
struct cardemu_usb_msg_tx_data *td;
|
||||
uint8_t byte;
|
||||
|
||||
/* ensure we are aware of any data that might be pending for
|
||||
* transmit */
|
||||
if (!ch->uart_tx_ctx) {
|
||||
/* uart_tx_queue is filled from main loop, so no need
|
||||
* for irq-safe operations */
|
||||
if (llist_empty(&ch->uart_tx_queue))
|
||||
return 0;
|
||||
|
||||
/* dequeue first at head */
|
||||
ch->uart_tx_ctx = llist_entry(ch->uart_tx_queue.next,
|
||||
struct req_ctx, list);
|
||||
llist_del(&ch->uart_tx_ctx->list);
|
||||
req_ctx_set_state(ch->uart_tx_ctx, RCTX_S_UART_TX_BUSY);
|
||||
|
||||
/* start with index zero */
|
||||
ch->uart_tx_ctx->idx = 0;
|
||||
|
||||
}
|
||||
rctx = ch->uart_tx_ctx;
|
||||
td = (struct cardemu_usb_msg_tx_data *) rctx->data;
|
||||
|
||||
/* take the next pending byte out of the rctx */
|
||||
byte = td->data[rctx->idx++];
|
||||
|
||||
card_emu_uart_tx(ch->uart_chan, byte);
|
||||
|
||||
/* this must happen _after_ the byte has been transmittd */
|
||||
switch (ch->tpdu.state) {
|
||||
case TPDU_S_WAIT_PB:
|
||||
/* if we just transmitted the procedure byte, we need to decide
|
||||
* if we want to continue to receive or transmit */
|
||||
if (td->flags & CEMU_DATA_F_PB_AND_TX)
|
||||
set_tpdu_state(ch, TPDU_S_WAIT_TX);
|
||||
else if (td->flags & CEMU_DATA_F_PB_AND_RX)
|
||||
set_tpdu_state(ch, TPDU_S_WAIT_RX);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* check if the buffer has now been fully transmitted */
|
||||
if ((rctx->idx >= td->data_len) ||
|
||||
(td->data + rctx->idx >= rctx->data + rctx->tot_len)) {
|
||||
if (td->flags & CEMU_DATA_F_PB_AND_RX) {
|
||||
/* we have just sent the procedure byte and now
|
||||
* need to continue receiving */
|
||||
set_tpdu_state(ch, TPDU_S_WAIT_RX);
|
||||
} else {
|
||||
/* we have transmitted all bytes */
|
||||
if (td->flags & CEMU_DATA_F_FINAL) {
|
||||
/* this was the final part of the APDU, go
|
||||
* back to state one */
|
||||
card_set_state(ch, ISO_S_WAIT_TPDU);
|
||||
}
|
||||
}
|
||||
req_ctx_set_state(rctx, RCTX_S_FREE);
|
||||
ch->uart_tx_ctx = NULL;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* Public API
|
||||
**********************************************************************/
|
||||
|
||||
/* process a single byte received from the reader */
|
||||
void card_emu_process_rx_byte(struct card_handle *ch, uint8_t byte)
|
||||
{
|
||||
int new_state = -1;
|
||||
|
||||
ch->stats.rx_bytes++;
|
||||
|
||||
switch (ch->state) {
|
||||
case ISO_S_WAIT_POWER:
|
||||
case ISO_S_WAIT_CLK:
|
||||
case ISO_S_WAIT_RST:
|
||||
case ISO_S_WAIT_ATR:
|
||||
TRACE_ERROR("%u: Received UART char in invalid 7816 state "
|
||||
"%u\r\n", ch->num, ch->state);
|
||||
/* we shouldn't receive any data from the reader yet! */
|
||||
break;
|
||||
case ISO_S_WAIT_TPDU:
|
||||
if (byte == 0xff) {
|
||||
new_state = process_byte_pts(ch, byte);
|
||||
ch->stats.pps++;
|
||||
goto out_silent;
|
||||
}
|
||||
/* fall-through */
|
||||
case ISO_S_IN_TPDU:
|
||||
new_state = process_byte_tpdu(ch, byte);
|
||||
break;
|
||||
case ISO_S_IN_PTS:
|
||||
new_state = process_byte_pts(ch, byte);
|
||||
goto out_silent;
|
||||
}
|
||||
|
||||
out_silent:
|
||||
if (new_state != -1)
|
||||
card_set_state(ch, new_state);
|
||||
}
|
||||
|
||||
/* transmit a single byte to the reader */
|
||||
int card_emu_tx_byte(struct card_handle *ch)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
switch (ch->state) {
|
||||
case ISO_S_IN_ATR:
|
||||
if (ch->atr.idx < ch->atr.len) {
|
||||
uint8_t byte;
|
||||
byte = ch->atr.atr[ch->atr.idx++];
|
||||
rc = 1;
|
||||
|
||||
card_emu_uart_tx(ch->uart_chan, byte);
|
||||
|
||||
/* detect end of ATR */
|
||||
if (ch->atr.idx >= ch->atr.len)
|
||||
card_set_state(ch, ISO_S_WAIT_TPDU);
|
||||
}
|
||||
break;
|
||||
case ISO_S_IN_PTS:
|
||||
rc = tx_byte_pts(ch);
|
||||
break;
|
||||
case ISO_S_IN_TPDU:
|
||||
rc = tx_byte_tpdu(ch);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (rc)
|
||||
ch->stats.tx_bytes++;
|
||||
|
||||
/* if we return 0 here, the UART needs to disable transmit-ready
|
||||
* interrupts */
|
||||
return rc;
|
||||
}
|
||||
|
||||
void card_emu_have_new_uart_tx(struct card_handle *ch)
|
||||
{
|
||||
switch (ch->state) {
|
||||
case ISO_S_IN_TPDU:
|
||||
switch (ch->tpdu.state) {
|
||||
case TPDU_S_WAIT_TX:
|
||||
case TPDU_S_WAIT_PB:
|
||||
card_emu_uart_enable(ch->uart_chan, ENABLE_TX);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void card_emu_report_status(struct card_handle *ch)
|
||||
{
|
||||
struct req_ctx *rctx;
|
||||
struct cardemu_usb_msg_status *sts;
|
||||
|
||||
rctx = req_ctx_find_get(0, RCTX_S_FREE, RCTX_S_UART_RX_BUSY);
|
||||
if (!rctx)
|
||||
return;
|
||||
|
||||
rctx->tot_len = sizeof(*sts);
|
||||
sts = (struct cardemu_usb_msg_status *)rctx->data;
|
||||
sts->hdr.msg_type = CEMU_USB_MSGT_DO_STATUS;
|
||||
sts->hdr.msg_len = sizeof(*sts);
|
||||
sts->flags = 0;
|
||||
if (ch->vcc_active)
|
||||
sts->flags |= CEMU_STATUS_F_VCC_PRESENT;
|
||||
if (ch->clocked)
|
||||
sts->flags |= CEMU_STATUS_F_CLK_ACTIVE;
|
||||
if (ch->in_reset)
|
||||
sts->flags |= CEMU_STATUS_F_RESET_ACTIVE;
|
||||
/* FIXME: voltage + card insert */
|
||||
sts->fi = ch->fi;
|
||||
sts->di = ch->di;
|
||||
sts->wi = ch->wi;
|
||||
sts->waiting_time = ch->waiting_time;
|
||||
|
||||
llist_add_tail(&rctx->list, &ch->usb_tx_queue);
|
||||
req_ctx_set_state(rctx, RCTX_S_USB_TX_PENDING);
|
||||
}
|
||||
|
||||
/* hardware driver informs us that a card I/O signal has changed */
|
||||
void card_emu_io_statechg(struct card_handle *ch, enum card_io io, int active)
|
||||
{
|
||||
switch (io) {
|
||||
case CARD_IO_VCC:
|
||||
if (active == 0 && ch->vcc_active == 1) {
|
||||
TRACE_INFO("%u: VCC deactivated\r\n", ch->num);
|
||||
tc_etu_disable(ch->tc_chan);
|
||||
card_set_state(ch, ISO_S_WAIT_POWER);
|
||||
} else if (active == 1 && ch->vcc_active == 0) {
|
||||
TRACE_INFO("%u: VCC activated\r\n", ch->num);
|
||||
card_set_state(ch, ISO_S_WAIT_CLK);
|
||||
}
|
||||
ch->vcc_active = active;
|
||||
break;
|
||||
case CARD_IO_CLK:
|
||||
if (active == 1 && ch->clocked == 0) {
|
||||
TRACE_INFO("%u: CLK activated\r\n", ch->num);
|
||||
if (ch->state == ISO_S_WAIT_CLK)
|
||||
card_set_state(ch, ISO_S_WAIT_RST);
|
||||
} else if (active == 0 && ch->clocked == 1) {
|
||||
TRACE_INFO("%u: CLK deactivated\r\n", ch->num);
|
||||
}
|
||||
ch->clocked = active;
|
||||
break;
|
||||
case CARD_IO_RST:
|
||||
if (active == 0 && ch->in_reset) {
|
||||
TRACE_INFO("%u: RST released\r\n", ch->num);
|
||||
if (ch->vcc_active && ch->clocked) {
|
||||
/* enable the TC/ETU counter once reset has been released */
|
||||
tc_etu_enable(ch->tc_chan);
|
||||
card_set_state(ch, ISO_S_WAIT_ATR);
|
||||
/* FIXME: wait 400 to 40k clock cycles before sending ATR */
|
||||
card_set_state(ch, ISO_S_IN_ATR);
|
||||
}
|
||||
} else if (active && !ch->in_reset) {
|
||||
TRACE_INFO("%u: RST asserted\r\n", ch->num);
|
||||
tc_etu_disable(ch->tc_chan);
|
||||
}
|
||||
ch->in_reset = active;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* User sets a new ATR to be returned during next card reset */
|
||||
int card_emu_set_atr(struct card_handle *ch, const uint8_t *atr, uint8_t len)
|
||||
{
|
||||
if (len > sizeof(ch->atr.atr))
|
||||
return -1;
|
||||
|
||||
memcpy(ch->atr.atr, atr, len);
|
||||
ch->atr.len = len;
|
||||
ch->atr.idx = 0;
|
||||
|
||||
/* FIXME: race condition with trasmitting ATR to reader? */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* hardware driver informs us that one (more) ETU has expired */
|
||||
void tc_etu_wtime_half_expired(void *handle)
|
||||
{
|
||||
struct card_handle *ch = handle;
|
||||
/* transmit NULL procedure byte well before waiting time expires */
|
||||
switch (ch->state) {
|
||||
case ISO_S_IN_TPDU:
|
||||
switch (ch->tpdu.state) {
|
||||
case TPDU_S_WAIT_PB:
|
||||
case TPDU_S_WAIT_TX:
|
||||
putchar('N');
|
||||
card_emu_uart_tx(ch->uart_chan, ISO7816_3_PB_NULL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* hardware driver informs us that one (more) ETU has expired */
|
||||
void tc_etu_wtime_expired(void *handle)
|
||||
{
|
||||
struct card_handle *ch = handle;
|
||||
TRACE_ERROR("%u: wtime_exp\r\n", ch->num);
|
||||
}
|
||||
|
||||
/* shortest ATR found in smartcard_list.txt */
|
||||
static const uint8_t default_atr[] = { 0x3B, 0x02, 0x14, 0x50 };
|
||||
|
||||
static struct card_handle card_handles[NUM_SLOTS];
|
||||
|
||||
struct card_handle *card_emu_init(uint8_t slot_num, uint8_t tc_chan, uint8_t uart_chan)
|
||||
{
|
||||
struct card_handle *ch;
|
||||
|
||||
if (slot_num >= ARRAY_SIZE(card_handles))
|
||||
return NULL;
|
||||
|
||||
ch = &card_handles[slot_num];
|
||||
|
||||
memset(ch, 0, sizeof(*ch));
|
||||
|
||||
INIT_LLIST_HEAD(&ch->usb_tx_queue);
|
||||
INIT_LLIST_HEAD(&ch->uart_tx_queue);
|
||||
|
||||
/* initialize the card_handle with reasonabe defaults */
|
||||
ch->num = slot_num;
|
||||
ch->state = ISO_S_WAIT_POWER;
|
||||
ch->vcc_active = 0;
|
||||
ch->in_reset = 1;
|
||||
ch->clocked = 0;
|
||||
|
||||
ch->fi = 0;
|
||||
ch->di = 1;
|
||||
ch->wi = ISO7816_3_DEFAULT_WI;
|
||||
|
||||
ch->tc_chan = tc_chan;
|
||||
ch->uart_chan = uart_chan;
|
||||
ch->waiting_time = ISO7816_3_INIT_WTIME;
|
||||
|
||||
ch->atr.idx = 0;
|
||||
ch->atr.len = sizeof(default_atr);
|
||||
memcpy(ch->atr.atr, default_atr, ch->atr.len);
|
||||
|
||||
ch->pts.state = PTS_S_WAIT_REQ_PTSS;
|
||||
ch->tpdu.state = TPDU_S_WAIT_CLA;
|
||||
|
||||
tc_etu_init(ch->tc_chan, ch);
|
||||
|
||||
return ch;
|
||||
}
|
||||
188
firmware/libcommon/source/ccid.c
Normal file
188
firmware/libcommon/source/ccid.c
Normal file
@@ -0,0 +1,188 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2009, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CCID
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Headers
|
||||
*------------------------------------------------------------------------------*/
|
||||
|
||||
#include "board.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Internal definitions
|
||||
*------------------------------------------------------------------------------*/
|
||||
/** Maximum ucSize in bytes of the smartcard answer to a command.*/
|
||||
#define MAX_ANSWER_SIZE 10
|
||||
|
||||
/** Maximum ATR ucSize in bytes.*/
|
||||
#define MAX_ATR_SIZE 55
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Internal variables
|
||||
*------------------------------------------------------------------------------*/
|
||||
|
||||
/** ISO7816 pins */
|
||||
static const Pin pinsISO7816[] = { PINS_ISO7816 };
|
||||
|
||||
/** Bus switch pins */
|
||||
static const Pin pinsBus[] = { PINS_BUS_DEFAULT };
|
||||
|
||||
/* SIMcard power pin */
|
||||
static const Pin pinsPower[] = { PWR_PINS };
|
||||
|
||||
/** ISO7816 RST pin */
|
||||
static const Pin pinIso7816RstMC = PIN_ISO7816_RSTMC;
|
||||
static uint8_t sim_inserted = 0;
|
||||
|
||||
static struct Usart_info usart_info = {
|
||||
.base = USART_SIM,
|
||||
.id = ID_USART_SIM,
|
||||
.state = USART_RCV
|
||||
};
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Optional smartcard detection
|
||||
*------------------------------------------------------------------------------*/
|
||||
|
||||
/** Smartcard detection pin.*/
|
||||
static const Pin pinSmartCard = SMARTCARD_CONNECT_PIN;
|
||||
|
||||
/**
|
||||
* PIO interrupt service routine. Checks if the smartcard has been connected
|
||||
* or disconnected.
|
||||
*/
|
||||
static void ISR_PioSmartCard(const Pin * pPin)
|
||||
{
|
||||
/* FIXME: why is pinSmartCard.pio->PIO_ISR the wrong number?
|
||||
printf("+++++ Trying to check for pending interrupts (PIO ISR: 0x%X)\n\r", pinSmartCard.pio->PIO_ISR);
|
||||
printf("+++++ Mask: 0x%X\n\r", pinSmartCard.mask);
|
||||
Output:
|
||||
+++++ Trying to check for pending interrupts (PIO ISR: 0x400)) = 1<<10
|
||||
+++++ Mask: 0x100 = 1<<8
|
||||
*/
|
||||
// PA10 is DTXD, which is the debug uart transmit pin
|
||||
|
||||
printf("Interrupt!!\n\r");
|
||||
/* Check all pending interrupts */
|
||||
// FIXME: this if condition is not always true...
|
||||
// if ( (pinSmartCard.pio->PIO_ISR & pinSmartCard.mask) != 0 )
|
||||
{
|
||||
/* Check current level on pin */
|
||||
if (PIO_Get(&pinSmartCard) == 0) {
|
||||
sim_inserted = 1;
|
||||
printf("-I- Smartcard inserted\n\r");
|
||||
CCID_Insertion();
|
||||
} else {
|
||||
sim_inserted = 0;
|
||||
printf("-I- Smartcard removed\n\r");
|
||||
CCID_Removal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the smartcard detection pin to trigger an interrupt.
|
||||
*/
|
||||
static void ConfigureCardDetection(void)
|
||||
{
|
||||
printf("+++++ Configure PIOs\n\r");
|
||||
PIO_Configure(&pinSmartCard, 1);
|
||||
NVIC_EnableIRQ(PIOA_IRQn);
|
||||
PIO_EnableIt(&pinSmartCard);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Initialization and run
|
||||
*-----------------------------------------------------------------------------*/
|
||||
extern CCIDDriverConfigurationDescriptors configurationDescriptorCCID;
|
||||
|
||||
void CCID_configure(void)
|
||||
{
|
||||
CCIDDriver_Initialize();
|
||||
// FIXME: Do we need to set priority?: NVIC_SetPriority( PIOA_IRQn, 10);
|
||||
PIO_ConfigureIt(&pinSmartCard, ISR_PioSmartCard);
|
||||
}
|
||||
|
||||
void CCID_exit(void)
|
||||
{
|
||||
PIO_DisableIt(&pinSmartCard);
|
||||
USART_SetTransmitterEnabled(usart_info.base, 0);
|
||||
USART_SetReceiverEnabled(usart_info.base, 0);
|
||||
}
|
||||
|
||||
void CCID_init(void)
|
||||
{
|
||||
uint8_t pAtr[MAX_ATR_SIZE];
|
||||
uint8_t ucSize;
|
||||
|
||||
// FIXME: do we want to print ATR?
|
||||
/* Initialize Atr buffer */
|
||||
memset(pAtr, 0, sizeof(pAtr));
|
||||
|
||||
ConfigureCardDetection();
|
||||
|
||||
// Configure ISO7816 driver
|
||||
PIO_Configure(pinsISO7816, PIO_LISTSIZE(pinsISO7816));
|
||||
PIO_Configure(pinsBus, PIO_LISTSIZE(pinsBus));
|
||||
PIO_Configure(pinsPower, PIO_LISTSIZE(pinsPower));
|
||||
|
||||
/* power up the card */
|
||||
// PIO_Set(&pinsPower[0]);
|
||||
|
||||
ISO7816_Init(&usart_info, CLK_MASTER);
|
||||
USART_SetTransmitterEnabled(usart_info.base, 1);
|
||||
USART_SetReceiverEnabled(usart_info.base, 1);
|
||||
|
||||
ISO7816_Set_Reset_Pin(&pinIso7816RstMC);
|
||||
/* Read ATR */
|
||||
ISO7816_warm_reset();
|
||||
|
||||
ISO7816_Datablock_ATR(pAtr, &ucSize);
|
||||
|
||||
/* Decode ATR and print it */
|
||||
ISO7816_Decode_ATR(pAtr);
|
||||
|
||||
// FIXME. what if smcard is not inserted?
|
||||
if (PIO_Get(&pinSmartCard) == 0) {
|
||||
printf("SIM card inserted\n\r");
|
||||
CCID_Insertion();
|
||||
}
|
||||
}
|
||||
|
||||
void CCID_run(void)
|
||||
{
|
||||
|
||||
//if (USBD_Read(INT, pBuffer, dLength, fCallback, pArgument);
|
||||
|
||||
CCID_SmartCardRequest();
|
||||
}
|
||||
#endif
|
||||
126
firmware/libcommon/source/host_communication.c
Normal file
126
firmware/libcommon/source/host_communication.c
Normal file
@@ -0,0 +1,126 @@
|
||||
//#define TRACE_LEVEL 6
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "board.h"
|
||||
#include "req_ctx.h"
|
||||
#include "osmocom/core/linuxlist.h"
|
||||
#include "llist_irqsafe.h"
|
||||
|
||||
static volatile uint32_t usbep_in_progress[BOARD_USB_NUMENDPOINTS];
|
||||
|
||||
/* call-back after (successful?) transfer of a buffer */
|
||||
static void usb_write_cb(uint8_t *arg, uint8_t status, uint32_t transferred,
|
||||
uint32_t remaining)
|
||||
{
|
||||
struct req_ctx *rctx = (struct req_ctx *) arg;
|
||||
|
||||
TRACE_DEBUG("%s (EP=%u)\r\n", __func__, rctx->ep);
|
||||
|
||||
__disable_irq();
|
||||
usbep_in_progress[rctx->ep]--;
|
||||
__enable_irq();
|
||||
TRACE_DEBUG("%u: in_progress=%d\n", rctx->ep, usbep_in_progress[rctx->ep]);
|
||||
|
||||
if (status != USBD_STATUS_SUCCESS)
|
||||
TRACE_ERROR("%s error, status=%d\n", __func__, status);
|
||||
|
||||
/* release request contxt to pool */
|
||||
req_ctx_set_state(rctx, RCTX_S_FREE);
|
||||
}
|
||||
|
||||
int usb_refill_to_host(struct llist_head *queue, uint32_t ep)
|
||||
{
|
||||
struct req_ctx *rctx;
|
||||
int rc;
|
||||
|
||||
__disable_irq();
|
||||
if (usbep_in_progress[ep]) {
|
||||
__enable_irq();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (llist_empty(queue)) {
|
||||
__enable_irq();
|
||||
return 0;
|
||||
}
|
||||
|
||||
usbep_in_progress[ep]++;
|
||||
|
||||
rctx = llist_entry(queue->next, struct req_ctx, list);
|
||||
llist_del(&rctx->list);
|
||||
|
||||
__enable_irq();
|
||||
|
||||
TRACE_DEBUG("%u: in_progress=%d\n", ep, usbep_in_progress[ep]);
|
||||
TRACE_DEBUG("%s (EP=%u)\r\n", __func__, ep);
|
||||
|
||||
req_ctx_set_state(rctx, RCTX_S_USB_TX_BUSY);
|
||||
rctx->ep = ep;
|
||||
|
||||
rc = USBD_Write(ep, rctx->data, rctx->tot_len,
|
||||
(TransferCallback) &usb_write_cb, rctx);
|
||||
if (rc != USBD_STATUS_SUCCESS) {
|
||||
TRACE_ERROR("%s error %x\n", __func__, rc);
|
||||
req_ctx_set_state(rctx, RCTX_S_USB_TX_PENDING);
|
||||
__disable_irq();
|
||||
usbep_in_progress[ep]--;
|
||||
__enable_irq();
|
||||
TRACE_DEBUG("%u: in_progress=%d\n", ep, usbep_in_progress[ep]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void usb_read_cb(uint8_t *arg, uint8_t status, uint32_t transferred,
|
||||
uint32_t remaining)
|
||||
{
|
||||
struct req_ctx *rctx = (struct req_ctx *) arg;
|
||||
struct llist_head *queue = (struct llist_head *) usbep_in_progress[rctx->ep];
|
||||
|
||||
TRACE_DEBUG("%s (EP=%u, len=%u, q=%p)\r\n", __func__,
|
||||
rctx->ep, transferred, queue);
|
||||
|
||||
usbep_in_progress[rctx->ep] = 0;
|
||||
|
||||
if (status != USBD_STATUS_SUCCESS) {
|
||||
TRACE_ERROR("%s error, status=%d\n", __func__, status);
|
||||
/* release request contxt to pool */
|
||||
req_ctx_put(rctx);
|
||||
return;
|
||||
}
|
||||
rctx->tot_len = transferred;
|
||||
req_ctx_set_state(rctx, RCTX_S_MAIN_PROCESSING);
|
||||
llist_add_tail_irqsafe(&rctx->list, queue);
|
||||
}
|
||||
|
||||
int usb_refill_from_host(struct llist_head *queue, int ep)
|
||||
{
|
||||
struct req_ctx *rctx;
|
||||
int rc;
|
||||
|
||||
if (usbep_in_progress[ep])
|
||||
return 0;
|
||||
|
||||
TRACE_DEBUG("%s (EP=%u)\r\n", __func__, ep);
|
||||
|
||||
rctx = req_ctx_find_get(0, RCTX_S_FREE, RCTX_S_USB_RX_BUSY);
|
||||
if (!rctx)
|
||||
return -ENOMEM;
|
||||
|
||||
rctx->ep = ep;
|
||||
usbep_in_progress[ep] = (uint32_t) queue;
|
||||
|
||||
rc = USBD_Read(ep, rctx->data, rctx->size,
|
||||
(TransferCallback) &usb_read_cb, rctx);
|
||||
|
||||
if (rc != USBD_STATUS_SUCCESS) {
|
||||
TRACE_ERROR("%s error %x\n", __func__, rc);
|
||||
req_ctx_put(rctx);
|
||||
usbep_in_progress[ep] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
688
firmware/libcommon/source/iso7816_4.c
Normal file
688
firmware/libcommon/source/iso7816_4.c
Normal file
@@ -0,0 +1,688 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2009, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \section Purpose
|
||||
*
|
||||
* ISO 7816 driver
|
||||
*
|
||||
* \section Usage
|
||||
*
|
||||
* Explanation on the usage of the code made available through the header file.
|
||||
*/
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Headers
|
||||
*------------------------------------------------------------------------------*/
|
||||
|
||||
#include "board.h"
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Definitions
|
||||
*------------------------------------------------------------------------------*/
|
||||
/** Case for APDU commands*/
|
||||
#define CASE1 1
|
||||
#define CASE2 2
|
||||
#define CASE3 3
|
||||
|
||||
/** Flip flop for send and receive char */
|
||||
#define USART_SEND 0
|
||||
#define USART_RCV 1
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Internal variables
|
||||
*-----------------------------------------------------------------------------*/
|
||||
/** Pin reset master card */
|
||||
static Pin *st_pinIso7816RstMC;
|
||||
|
||||
struct Usart_info usart_sim = {.base = USART_SIM, .id = ID_USART_SIM, .state = USART_RCV};
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* Internal functions
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Get a character from ISO7816
|
||||
* \param pCharToReceive Pointer for store the received char
|
||||
* \return 0: if timeout else status of US_CSR
|
||||
*/
|
||||
uint32_t ISO7816_GetChar( uint8_t *pCharToReceive, Usart_info *usart)
|
||||
{
|
||||
uint32_t status;
|
||||
uint32_t timeout=0;
|
||||
|
||||
Usart *us_base = usart->base;
|
||||
uint32_t us_id = usart->id;
|
||||
|
||||
if( usart->state == USART_SEND ) {
|
||||
while((us_base->US_CSR & US_CSR_TXEMPTY) == 0) {}
|
||||
us_base->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
|
||||
usart->state = USART_RCV;
|
||||
}
|
||||
|
||||
/* Wait USART ready for reception */
|
||||
while( ((us_base->US_CSR & US_CSR_RXRDY) == 0) ) {
|
||||
if(timeout++ > 12000 * (BOARD_MCK/1000000)) {
|
||||
TRACE_WARNING("TimeOut\n\r");
|
||||
return( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
/* At least one complete character has been received and US_RHR has not yet been read. */
|
||||
|
||||
/* Get a char */
|
||||
*pCharToReceive = ((us_base->US_RHR) & 0xFF);
|
||||
|
||||
status = (us_base->US_CSR&(US_CSR_OVRE|US_CSR_FRAME|
|
||||
US_CSR_PARE|US_CSR_TIMEOUT|US_CSR_NACK|
|
||||
(1<<10)));
|
||||
|
||||
if (status != 0 ) {
|
||||
TRACE_DEBUG("R:0x%" PRIX32 "\n\r", status);
|
||||
TRACE_DEBUG("R:0x%" PRIX32 "\n\r", us_base->US_CSR);
|
||||
TRACE_DEBUG("Nb:0x%" PRIX32 "\n\r", us_base->US_NER );
|
||||
us_base->US_CR = US_CR_RSTSTA;
|
||||
}
|
||||
|
||||
/* Return status */
|
||||
return( status );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send a char to ISO7816
|
||||
* \param CharToSend char to be send
|
||||
* \return status of US_CSR
|
||||
*/
|
||||
uint32_t ISO7816_SendChar( uint8_t CharToSend, Usart_info *usart )
|
||||
{
|
||||
uint32_t status;
|
||||
|
||||
Usart *us_base = usart->base;
|
||||
uint32_t us_id = usart->id;
|
||||
|
||||
if( usart->state == USART_RCV ) {
|
||||
us_base->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
|
||||
usart->state = USART_SEND;
|
||||
}
|
||||
|
||||
/* Wait USART ready for transmit */
|
||||
int i = 0;
|
||||
while((us_base->US_CSR & (US_CSR_TXRDY)) == 0) {
|
||||
i++;
|
||||
if (!(i%1000000)) {
|
||||
printf("s: %x ", us_base->US_CSR);
|
||||
printf("s: %x\r\n", us_base->US_RHR & 0xFF);
|
||||
us_base->US_CR = US_CR_RSTTX;
|
||||
us_base->US_CR = US_CR_RSTRX;
|
||||
}
|
||||
}
|
||||
/* There is no character in the US_THR */
|
||||
|
||||
/* Transmit a char */
|
||||
us_base->US_THR = CharToSend;
|
||||
|
||||
TRACE_ERROR("Sx%02X\r\n", CharToSend);
|
||||
|
||||
status = (us_base->US_CSR&(US_CSR_OVRE|US_CSR_FRAME|
|
||||
US_CSR_PARE|US_CSR_TIMEOUT|US_CSR_NACK|
|
||||
(1<<10)));
|
||||
|
||||
if (status != 0 ) {
|
||||
TRACE_INFO("******* status: 0x%" PRIX32 " (Overrun: %" PRIX32
|
||||
", NACK: %" PRIX32 ", Timeout: %" PRIX32 ", underrun: %" PRIX32 ")\n\r",
|
||||
status, ((status & US_CSR_OVRE)>> 5), ((status & US_CSR_NACK) >> 13),
|
||||
((status & US_CSR_TIMEOUT) >> 8), ((status & (1 << 10)) >> 10));
|
||||
TRACE_INFO("E (USART CSR reg):0x%" PRIX32 "\n\r", us_base->US_CSR);
|
||||
TRACE_INFO("Nb (Number of errors):0x%" PRIX32 "\n\r", us_base->US_NER );
|
||||
us_base->US_CR = US_CR_RSTSTA;
|
||||
}
|
||||
|
||||
/* Return status */
|
||||
return( status );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Iso 7816 ICC power on
|
||||
*/
|
||||
static void ISO7816_IccPowerOn( void )
|
||||
{
|
||||
/* Set RESET Master Card */
|
||||
if (st_pinIso7816RstMC) {
|
||||
PIO_Set(st_pinIso7816RstMC);
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* Exported functions
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Iso 7816 ICC power off
|
||||
*/
|
||||
void ISO7816_IccPowerOff( void )
|
||||
{
|
||||
/* Clear RESET Master Card */
|
||||
if (st_pinIso7816RstMC) {
|
||||
PIO_Clear(st_pinIso7816RstMC);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transfert Block TPDU T=0
|
||||
* \param pAPDU APDU buffer
|
||||
* \param pMessage Message buffer
|
||||
* \param wLength Block length
|
||||
* \param indexMsg Message index
|
||||
* \return 0 on success, content of US_CSR otherwise
|
||||
*/
|
||||
uint32_t ISO7816_XfrBlockTPDU_T0(const uint8_t *pAPDU,
|
||||
uint8_t *pMessage,
|
||||
uint16_t wLength,
|
||||
uint16_t *retlen )
|
||||
{
|
||||
uint16_t NeNc;
|
||||
uint16_t indexApdu = 4;
|
||||
uint16_t indexMsg = 0;
|
||||
uint8_t SW1 = 0;
|
||||
uint8_t procByte;
|
||||
uint8_t cmdCase;
|
||||
uint32_t status = 0;
|
||||
|
||||
TRACE_INFO("pAPDU[0]=0x%X\n\r",pAPDU[0]);
|
||||
TRACE_INFO("pAPDU[1]=0x%X\n\r",pAPDU[1]);
|
||||
TRACE_INFO("pAPDU[2]=0x%X\n\r",pAPDU[2]);
|
||||
TRACE_INFO("pAPDU[3]=0x%X\n\r",pAPDU[3]);
|
||||
TRACE_INFO("pAPDU[4]=0x%X\n\r",pAPDU[4]);
|
||||
TRACE_INFO("pAPDU[5]=0x%X\n\r",pAPDU[5]);
|
||||
TRACE_INFO("wlength=%d\n\r",wLength);
|
||||
|
||||
ISO7816_SendChar( pAPDU[0], &usart_sim ); /* CLA */
|
||||
ISO7816_SendChar( pAPDU[1], &usart_sim ); /* INS */
|
||||
ISO7816_SendChar( pAPDU[2], &usart_sim ); /* P1 */
|
||||
ISO7816_SendChar( pAPDU[3], &usart_sim ); /* P2 */
|
||||
ISO7816_SendChar( pAPDU[4], &usart_sim ); /* P3 */
|
||||
|
||||
/* Handle the four structures of command APDU */
|
||||
indexApdu = 5;
|
||||
|
||||
if( wLength == 4 ) {
|
||||
cmdCase = CASE1;
|
||||
NeNc = 0;
|
||||
}
|
||||
else if( wLength == 5) {
|
||||
cmdCase = CASE2;
|
||||
NeNc = pAPDU[4]; /* C5 */
|
||||
if (NeNc == 0) {
|
||||
NeNc = 256;
|
||||
}
|
||||
}
|
||||
else if( wLength == 6) {
|
||||
NeNc = pAPDU[4]; /* C5 */
|
||||
cmdCase = CASE3;
|
||||
}
|
||||
else if( wLength == 7) {
|
||||
NeNc = pAPDU[4]; /* C5 */
|
||||
if( NeNc == 0 ) {
|
||||
cmdCase = CASE2;
|
||||
NeNc = (pAPDU[5]<<8)+pAPDU[6];
|
||||
}
|
||||
else {
|
||||
cmdCase = CASE3;
|
||||
}
|
||||
}
|
||||
else {
|
||||
NeNc = pAPDU[4]; /* C5 */
|
||||
if( NeNc == 0 ) {
|
||||
cmdCase = CASE3;
|
||||
NeNc = (pAPDU[5]<<8)+pAPDU[6];
|
||||
}
|
||||
else {
|
||||
cmdCase = CASE3;
|
||||
}
|
||||
}
|
||||
|
||||
TRACE_DEBUG("CASE=0x%X NeNc=0x%X\n\r", cmdCase, NeNc);
|
||||
|
||||
/* Handle Procedure Bytes */
|
||||
do {
|
||||
status = ISO7816_GetChar(&procByte, &usart_sim);
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
TRACE_INFO("procByte: 0x%X\n\r", procByte);
|
||||
/* Handle NULL */
|
||||
if ( procByte == ISO_NULL_VAL ) {
|
||||
TRACE_INFO("INS\n\r");
|
||||
continue;
|
||||
}
|
||||
/* Handle SW1 */
|
||||
else if ( ((procByte & 0xF0) ==0x60) || ((procByte & 0xF0) ==0x90) ) {
|
||||
TRACE_INFO("SW1\n\r");
|
||||
SW1 = 1;
|
||||
}
|
||||
/* Handle INS */
|
||||
else if ( pAPDU[1] == procByte) {
|
||||
TRACE_INFO("HdlINS\n\r");
|
||||
if (cmdCase == CASE2) {
|
||||
/* receive data from card */
|
||||
do {
|
||||
status = ISO7816_GetChar(&pMessage[indexMsg++], &usart_sim);
|
||||
} while(( 0 != --NeNc) && (status == 0) );
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Send data */
|
||||
do {
|
||||
TRACE_INFO("Send %X", pAPDU[indexApdu]);
|
||||
ISO7816_SendChar(pAPDU[indexApdu++], &usart_sim);
|
||||
} while( 0 != --NeNc );
|
||||
}
|
||||
}
|
||||
/* Handle INS ^ 0xff */
|
||||
else
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wsign-compare"
|
||||
if ( pAPDU[1] == (procByte ^ 0xff)) {
|
||||
#pragma GCC diagnostic pop
|
||||
TRACE_INFO("HdlINS+\n\r");
|
||||
if (cmdCase == CASE2) {
|
||||
/* receive data from card */
|
||||
status = ISO7816_GetChar(&pMessage[indexMsg++], &usart_sim);
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
TRACE_INFO("Rcv: 0x%X\n\r", pMessage[indexMsg-1]);
|
||||
}
|
||||
else {
|
||||
status = ISO7816_SendChar(pAPDU[indexApdu++], &usart_sim);
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
NeNc--;
|
||||
}
|
||||
else {
|
||||
/* ?? */
|
||||
TRACE_INFO("procByte=0x%X\n\r", procByte);
|
||||
break;
|
||||
}
|
||||
} while (NeNc != 0);
|
||||
|
||||
/* Status Bytes */
|
||||
if (SW1 == 0) {
|
||||
status = ISO7816_GetChar(&pMessage[indexMsg++], &usart_sim); /* SW1 */
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
else {
|
||||
pMessage[indexMsg++] = procByte;
|
||||
}
|
||||
status = ISO7816_GetChar(&pMessage[indexMsg++], &usart_sim); /* SW2 */
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
TRACE_WARNING("SW1=0x%X, SW2=0x%X\n\r", pMessage[indexMsg-2], pMessage[indexMsg-1]);
|
||||
|
||||
*retlen = indexMsg;
|
||||
return status;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape ISO7816
|
||||
*/
|
||||
void ISO7816_Escape( void )
|
||||
{
|
||||
TRACE_DEBUG("For user, if needed\n\r");
|
||||
}
|
||||
|
||||
/**
|
||||
* Restart clock ISO7816
|
||||
*/
|
||||
void ISO7816_RestartClock( void )
|
||||
{
|
||||
TRACE_DEBUG("ISO7816_RestartClock\n\r");
|
||||
USART_SIM->US_BRGR = 13;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop clock ISO7816
|
||||
*/
|
||||
void ISO7816_StopClock( void )
|
||||
{
|
||||
TRACE_DEBUG("ISO7816_StopClock\n\r");
|
||||
USART_SIM->US_BRGR = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* T0 APDU
|
||||
*/
|
||||
void ISO7816_toAPDU( void )
|
||||
{
|
||||
TRACE_DEBUG("ISO7816_toAPDU\n\r");
|
||||
TRACE_DEBUG("Not supported at this time\n\r");
|
||||
}
|
||||
|
||||
/**
|
||||
* Answer To Reset (ATR)
|
||||
* \param pAtr ATR buffer
|
||||
* \param pLength Pointer for store the ATR length
|
||||
* \return 0: if timeout else status of US_CSR
|
||||
*/
|
||||
uint32_t ISO7816_Datablock_ATR( uint8_t* pAtr, uint8_t* pLength )
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t j;
|
||||
uint32_t y;
|
||||
uint32_t status = 0;
|
||||
|
||||
*pLength = 0;
|
||||
|
||||
/* Read ATR TS */
|
||||
// FIXME: There should always be a check for the GetChar return value..0 means timeout
|
||||
status = ISO7816_GetChar(&pAtr[0], &usart_sim);
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Read ATR T0 */
|
||||
status = ISO7816_GetChar(&pAtr[1], &usart_sim);
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
y = pAtr[1] & 0xF0;
|
||||
i = 2;
|
||||
|
||||
/* Read ATR Ti */
|
||||
while (y && (status == 0)) {
|
||||
|
||||
if (y & 0x10) { /* TA[i] */
|
||||
status = ISO7816_GetChar(&pAtr[i++], &usart_sim);
|
||||
}
|
||||
if (y & 0x20) { /* TB[i] */
|
||||
status = ISO7816_GetChar(&pAtr[i++], &usart_sim);
|
||||
}
|
||||
if (y & 0x40) { /* TC[i] */
|
||||
status = ISO7816_GetChar(&pAtr[i++], &usart_sim);
|
||||
}
|
||||
if (y & 0x80) { /* TD[i] */
|
||||
status = ISO7816_GetChar(&pAtr[i], &usart_sim);
|
||||
y = pAtr[i++] & 0xF0;
|
||||
}
|
||||
else {
|
||||
y = 0;
|
||||
}
|
||||
}
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Historical Bytes */
|
||||
y = pAtr[1] & 0x0F;
|
||||
for( j=0; (j < y) && (status == 0); j++ ) {
|
||||
status = ISO7816_GetChar(&pAtr[i++], &usart_sim);
|
||||
}
|
||||
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
|
||||
*pLength = i;
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set data rate and clock frequency
|
||||
* \param dwClockFrequency ICC clock frequency in KHz.
|
||||
* \param dwDataRate ICC data rate in bpd
|
||||
*/
|
||||
void ISO7816_SetDataRateandClockFrequency( uint32_t dwClockFrequency, uint32_t dwDataRate )
|
||||
{
|
||||
uint8_t ClockFrequency;
|
||||
|
||||
/* Define the baud rate divisor register */
|
||||
/* CD = MCK / SCK */
|
||||
/* SCK = FIDI x BAUD = 372 x 9600 */
|
||||
/* BOARD_MCK */
|
||||
/* CD = MCK/(FIDI x BAUD) = 48000000 / (372x9600) = 13 */
|
||||
USART_SIM->US_BRGR = BOARD_MCK / (dwClockFrequency*1000);
|
||||
|
||||
ClockFrequency = BOARD_MCK / USART_SIM->US_BRGR;
|
||||
|
||||
USART_SIM->US_FIDI = (ClockFrequency)/dwDataRate;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Pin status for ISO7816 RESET
|
||||
* \return 1 if the Pin RstMC is high; otherwise 0.
|
||||
*/
|
||||
uint8_t ISO7816_StatusReset( void )
|
||||
{
|
||||
if (st_pinIso7816RstMC) {
|
||||
return PIO_Get(st_pinIso7816RstMC);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* cold reset
|
||||
*/
|
||||
void ISO7816_cold_reset( void )
|
||||
{
|
||||
volatile uint32_t i;
|
||||
|
||||
/* tb: wait ??? cycles*/
|
||||
for( i=0; i<(400*(BOARD_MCK/1000000)); i++ ) {
|
||||
}
|
||||
|
||||
USART_SIM->US_RHR;
|
||||
USART_SIM->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
|
||||
|
||||
ISO7816_IccPowerOn();
|
||||
}
|
||||
|
||||
/**
|
||||
* Warm reset
|
||||
*/
|
||||
void ISO7816_warm_reset( void )
|
||||
{
|
||||
volatile uint32_t i;
|
||||
|
||||
// Clears Reset
|
||||
ISO7816_IccPowerOff();
|
||||
|
||||
/* tb: wait ??? cycles */
|
||||
for( i=0; i<(400*(BOARD_MCK/1000000)); i++ ) {
|
||||
}
|
||||
|
||||
USART_SIM->US_RHR;
|
||||
USART_SIM->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
|
||||
|
||||
// Sets Reset
|
||||
ISO7816_IccPowerOn();
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode ATR trace
|
||||
* \param pAtr pointer on ATR buffer
|
||||
*/
|
||||
void ISO7816_Decode_ATR( uint8_t* pAtr )
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_t j;
|
||||
uint32_t y;
|
||||
uint8_t offset;
|
||||
|
||||
printf("\n\r");
|
||||
printf("ATR: Answer To Reset:\n\r");
|
||||
printf("TS = 0x%X Initial character ",pAtr[0]);
|
||||
if( pAtr[0] == 0x3B ) {
|
||||
|
||||
printf("Direct Convention\n\r");
|
||||
}
|
||||
else {
|
||||
if( pAtr[0] == 0x3F ) {
|
||||
|
||||
printf("Inverse Convention\n\r");
|
||||
}
|
||||
else {
|
||||
printf("BAD Convention\n\r");
|
||||
}
|
||||
}
|
||||
|
||||
printf("T0 = 0x%X Format caracter\n\r",pAtr[1]);
|
||||
printf(" Number of historical bytes: K = %d\n\r", pAtr[1]&0x0F);
|
||||
printf(" Presence further interface byte:\n\r");
|
||||
if( pAtr[1]&0x80 ) {
|
||||
printf("TA ");
|
||||
}
|
||||
if( pAtr[1]&0x40 ) {
|
||||
printf("TB ");
|
||||
}
|
||||
if( pAtr[1]&0x20 ) {
|
||||
printf("TC ");
|
||||
}
|
||||
if( pAtr[1]&0x10 ) {
|
||||
printf("TD ");
|
||||
}
|
||||
if( pAtr[1] != 0 ) {
|
||||
printf(" present\n\r");
|
||||
}
|
||||
|
||||
i = 2;
|
||||
y = pAtr[1] & 0xF0;
|
||||
|
||||
/* Read ATR Ti */
|
||||
offset = 1;
|
||||
while (y) {
|
||||
|
||||
if (y & 0x10) { /* TA[i] */
|
||||
printf("TA[%d] = 0x%X ", offset, pAtr[i]);
|
||||
if( offset == 1 ) {
|
||||
printf("FI = %d ", (pAtr[i]>>8));
|
||||
printf("DI = %d", (pAtr[i]&0x0F));
|
||||
}
|
||||
printf("\n\r");
|
||||
i++;
|
||||
}
|
||||
if (y & 0x20) { /* TB[i] */
|
||||
printf("TB[%d] = 0x%X\n\r", offset, pAtr[i]);
|
||||
i++;
|
||||
}
|
||||
if (y & 0x40) { /* TC[i] */
|
||||
printf("TC[%d] = 0x%X ", offset, pAtr[i]);
|
||||
if( offset == 1 ) {
|
||||
printf("Extra Guard Time: N = %d", pAtr[i]);
|
||||
}
|
||||
printf("\n\r");
|
||||
i++;
|
||||
}
|
||||
if (y & 0x80) { /* TD[i] */
|
||||
printf("TD[%d] = 0x%X\n\r", offset, pAtr[i]);
|
||||
y = pAtr[i++] & 0xF0;
|
||||
}
|
||||
else {
|
||||
y = 0;
|
||||
}
|
||||
offset++;
|
||||
}
|
||||
|
||||
/* Historical Bytes */
|
||||
printf("Historical bytes:\n\r");
|
||||
y = pAtr[1] & 0x0F;
|
||||
for( j=0; j < y; j++ ) {
|
||||
printf(" 0x%X", pAtr[i]);
|
||||
i++;
|
||||
}
|
||||
printf("\n\r\n\r");
|
||||
|
||||
}
|
||||
|
||||
void ISO7816_Set_Reset_Pin(const Pin *pPinIso7816RstMC) {
|
||||
/* Pin ISO7816 initialize */
|
||||
st_pinIso7816RstMC = (Pin *)pPinIso7816RstMC;
|
||||
}
|
||||
|
||||
/** Initializes a ISO driver
|
||||
* \param pPinIso7816RstMC Pin ISO 7816 Rst MC
|
||||
*/
|
||||
void ISO7816_Init( Usart_info *usart, bool master_clock )
|
||||
{
|
||||
uint32_t clk;
|
||||
TRACE_DEBUG("ISO_Init\n\r");
|
||||
|
||||
Usart *us_base = usart->base;
|
||||
uint32_t us_id = usart->id;
|
||||
|
||||
if (master_clock == true) {
|
||||
clk = US_MR_USCLKS_MCK;
|
||||
} else {
|
||||
clk = US_MR_USCLKS_SCK;
|
||||
}
|
||||
|
||||
USART_Configure( us_base,
|
||||
US_MR_USART_MODE_IS07816_T_0
|
||||
| clk
|
||||
| US_MR_NBSTOP_1_BIT
|
||||
| US_MR_PAR_EVEN
|
||||
| US_MR_CHRL_8_BIT
|
||||
| US_MR_CLKO
|
||||
| US_MR_INACK /* Inhibit errors */
|
||||
| (3<<24), /* MAX_ITERATION */
|
||||
1,
|
||||
0);
|
||||
|
||||
/* Disable interrupts */
|
||||
us_base->US_IDR = (uint32_t) -1;
|
||||
|
||||
/* Configure USART */
|
||||
PMC_EnablePeripheral(us_id);
|
||||
|
||||
us_base->US_FIDI = 372; /* by default */
|
||||
/* Define the baud rate divisor register */
|
||||
/* CD = MCK / SCK */
|
||||
/* SCK = FIDI x BAUD = 372 x 9600 */
|
||||
/* BOARD_MCK */
|
||||
/* CD = MCK/(FIDI x BAUD) = 48000000 / (372x9600) = 13 */
|
||||
if (master_clock == true) {
|
||||
us_base->US_BRGR = BOARD_MCK / (372*9600);
|
||||
} else {
|
||||
us_base->US_BRGR = US_BRGR_CD(1);
|
||||
}
|
||||
}
|
||||
|
||||
67
firmware/libcommon/source/mitm.c
Normal file
67
firmware/libcommon/source/mitm.c
Normal file
@@ -0,0 +1,67 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2009, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifdef HAVE_MITM
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Headers
|
||||
*------------------------------------------------------------------------------*/
|
||||
|
||||
#include "board.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static const Pin pins_bus[] = { PINS_BUS_DEFAULT };
|
||||
|
||||
void MITM_configure(void)
|
||||
{
|
||||
Phone_configure();
|
||||
CCID_configure();
|
||||
}
|
||||
|
||||
void MITM_init(void)
|
||||
{
|
||||
CCID_init();
|
||||
Phone_init();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void MITM_exit(void)
|
||||
{
|
||||
Phone_exit();
|
||||
CCID_exit();
|
||||
}
|
||||
|
||||
void MITM_run(void)
|
||||
{
|
||||
Phone_run();
|
||||
CCID_run();
|
||||
}
|
||||
#endif /* HAVE_MITM */
|
||||
572
firmware/libcommon/source/mode_cardemu.c
Normal file
572
firmware/libcommon/source/mode_cardemu.c
Normal file
@@ -0,0 +1,572 @@
|
||||
//#define TRACE_LEVEL 6
|
||||
|
||||
#include "board.h"
|
||||
#include "simtrace.h"
|
||||
#include "ringbuffer.h"
|
||||
#include "card_emu.h"
|
||||
#include "iso7816_fidi.h"
|
||||
#include "utils.h"
|
||||
#include "osmocom/core/linuxlist.h"
|
||||
#include "llist_irqsafe.h"
|
||||
#include "req_ctx.h"
|
||||
#include "cardemu_prot.h"
|
||||
|
||||
#define TRACE_ENTRY() TRACE_DEBUG("%s entering\r\n", __func__)
|
||||
|
||||
static const Pin pins_cardsim[] = PINS_CARDSIM;
|
||||
|
||||
/* UART pins */
|
||||
static const Pin pins_usim1[] = {PINS_USIM1};
|
||||
static const Pin pin_usim1_rst = PIN_USIM1_nRST;
|
||||
static const Pin pin_usim1_vcc = PIN_USIM1_VCC;
|
||||
|
||||
#ifdef CARDEMU_SECOND_UART
|
||||
static const Pin pins_usim2[] = {PINS_USIM2};
|
||||
static const Pin pin_usim2_rst = PIN_USIM2_nRST;
|
||||
static const Pin pin_usim2_vcc = PIN_USIM2_VCC;
|
||||
#endif
|
||||
|
||||
struct cardem_inst {
|
||||
uint32_t num;
|
||||
struct card_handle *ch;
|
||||
struct llist_head usb_out_queue;
|
||||
struct ringbuf rb;
|
||||
struct Usart_info usart_info;
|
||||
int usb_pending_old;
|
||||
uint8_t ep_out;
|
||||
uint8_t ep_in;
|
||||
uint8_t ep_int;
|
||||
const Pin pin_insert;
|
||||
uint32_t vcc_uv;
|
||||
uint32_t vcc_uv_last;
|
||||
};
|
||||
|
||||
static struct cardem_inst cardem_inst[] = {
|
||||
{
|
||||
.num = 0,
|
||||
.usart_info = {
|
||||
.base = USART1,
|
||||
.id = ID_USART1,
|
||||
.state = USART_RCV
|
||||
},
|
||||
.ep_out = PHONE_DATAOUT,
|
||||
.ep_in = PHONE_DATAIN,
|
||||
.ep_int = PHONE_INT,
|
||||
.pin_insert = PIN_SET_USIM1_PRES,
|
||||
},
|
||||
#ifdef CARDEMU_SECOND_UART
|
||||
{
|
||||
.num = 1,
|
||||
.usart_info = {
|
||||
.base = USART0,
|
||||
.id = ID_USART0,
|
||||
.state = USART_RCV
|
||||
},
|
||||
.ep_out = CARDEM_USIM2_DATAOUT,
|
||||
.ep_in = CARDEM_USIM2_DATAIN,
|
||||
.ep_int = CARDEM_USIM2_INT,
|
||||
.pin_insert = PIN_SET_USIM2_PRES,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
static Usart *get_usart_by_chan(uint8_t uart_chan)
|
||||
{
|
||||
switch (uart_chan) {
|
||||
case 0:
|
||||
return USART1;
|
||||
#ifdef CARDEMU_SECOND_UART
|
||||
case 1:
|
||||
return USART0;
|
||||
#endif
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Call-Backs from card_emu.c
|
||||
***********************************************************************/
|
||||
|
||||
static void wait_tx_idle(Usart *usart)
|
||||
{
|
||||
int i = 1;
|
||||
|
||||
/* wait until last char has been fully transmitted */
|
||||
while ((usart->US_CSR & (US_CSR_TXEMPTY)) == 0) {
|
||||
if (!(i%1000000)) {
|
||||
TRACE_ERROR("s: %x \r\n", usart->US_CSR);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void card_emu_uart_wait_tx_idle(uint8_t uart_chan)
|
||||
{
|
||||
Usart *usart = get_usart_by_chan(uart_chan);
|
||||
wait_tx_idle(usart);
|
||||
}
|
||||
|
||||
/* call-back from card_emu.c to enable/disable transmit and/or receive */
|
||||
void card_emu_uart_enable(uint8_t uart_chan, uint8_t rxtx)
|
||||
{
|
||||
Usart *usart = get_usart_by_chan(uart_chan);
|
||||
switch (rxtx) {
|
||||
case ENABLE_TX:
|
||||
USART_DisableIt(usart, ~US_IER_TXRDY);
|
||||
/* as irritating as it is, we actually want to keep the
|
||||
* receiver enabled during transmit */
|
||||
USART_SetReceiverEnabled(usart, 1);
|
||||
usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
|
||||
USART_EnableIt(usart, US_IER_TXRDY);
|
||||
USART_SetTransmitterEnabled(usart, 1);
|
||||
break;
|
||||
case ENABLE_RX:
|
||||
USART_DisableIt(usart, ~US_IER_RXRDY);
|
||||
/* as irritating as it is, we actually want to keep the
|
||||
* transmitter enabled during receive */
|
||||
USART_SetTransmitterEnabled(usart, 1);
|
||||
wait_tx_idle(usart);
|
||||
usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
|
||||
USART_EnableIt(usart, US_IER_RXRDY);
|
||||
USART_SetReceiverEnabled(usart, 1);
|
||||
break;
|
||||
case 0:
|
||||
default:
|
||||
USART_SetTransmitterEnabled(usart, 0);
|
||||
USART_SetReceiverEnabled(usart, 0);
|
||||
USART_DisableIt(usart, 0xFFFFFFFF);
|
||||
usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* call-back from card_emu.c to transmit a byte */
|
||||
int card_emu_uart_tx(uint8_t uart_chan, uint8_t byte)
|
||||
{
|
||||
Usart *usart = get_usart_by_chan(uart_chan);
|
||||
#if 0
|
||||
Usart_info *ui = &usart_info[uart_chan];
|
||||
ISO7816_SendChar(byte, ui);
|
||||
#else
|
||||
int i = 1;
|
||||
while ((usart->US_CSR & (US_CSR_TXRDY)) == 0) {
|
||||
if (!(i%1000000)) {
|
||||
TRACE_ERROR("%u: s: %x %02X\r\n",
|
||||
uart_chan, usart->US_CSR,
|
||||
usart->US_RHR & 0xFF);
|
||||
usart->US_CR = US_CR_RSTTX;
|
||||
usart->US_CR = US_CR_RSTRX;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
usart->US_THR = byte;
|
||||
//TRACE_ERROR("Sx%02x\r\n", byte);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* FIXME: integrate this with actual irq handler */
|
||||
static void usart_irq_rx(uint8_t inst_num)
|
||||
{
|
||||
Usart *usart = get_usart_by_chan(inst_num);
|
||||
struct cardem_inst *ci = &cardem_inst[inst_num];
|
||||
uint32_t csr;
|
||||
uint8_t byte = 0;
|
||||
|
||||
csr = usart->US_CSR & usart->US_IMR;
|
||||
|
||||
if (csr & US_CSR_RXRDY) {
|
||||
byte = (usart->US_RHR) & 0xFF;
|
||||
rbuf_write(&ci->rb, byte);
|
||||
}
|
||||
|
||||
if (csr & US_CSR_TXRDY) {
|
||||
if (card_emu_tx_byte(ci->ch) == 0)
|
||||
USART_DisableIt(usart, US_IER_TXRDY);
|
||||
}
|
||||
|
||||
if (csr & (US_CSR_OVRE|US_CSR_FRAME|US_CSR_PARE|
|
||||
US_CSR_TIMEOUT|US_CSR_NACK|(1<<10))) {
|
||||
usart->US_CR = US_CR_RSTSTA | US_CR_RSTIT | US_CR_RSTNACK;
|
||||
TRACE_ERROR("%u e 0x%x st: 0x%x\n", ci->num, byte, csr);
|
||||
}
|
||||
}
|
||||
|
||||
void mode_cardemu_usart0_irq(void)
|
||||
{
|
||||
/* USART0 == Instance 1 == USIM 2 */
|
||||
usart_irq_rx(1);
|
||||
}
|
||||
|
||||
void mode_cardemu_usart1_irq(void)
|
||||
{
|
||||
/* USART1 == Instance 0 == USIM 1 */
|
||||
usart_irq_rx(0);
|
||||
}
|
||||
|
||||
/* call-back from card_emu.c to change UART baud rate */
|
||||
int card_emu_uart_update_fidi(uint8_t uart_chan, unsigned int fidi)
|
||||
{
|
||||
int rc;
|
||||
Usart *usart = get_usart_by_chan(uart_chan);
|
||||
|
||||
usart->US_CR |= US_CR_RXDIS | US_CR_RSTRX;
|
||||
usart->US_FIDI = fidi & 0x3ff;
|
||||
usart->US_CR |= US_CR_RXEN | US_CR_STTTO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* ADC for VCC voltage detection
|
||||
***********************************************************************/
|
||||
|
||||
#ifdef DETECT_VCC_BY_ADC
|
||||
|
||||
static int adc_triggered = 0;
|
||||
static int adc_sam3s_reva_errata = 0;
|
||||
|
||||
static int card_vcc_adc_init(void)
|
||||
{
|
||||
uint32_t chip_arch = CHIPID->CHIPID_CIDR & CHIPID_CIDR_ARCH_Msk;
|
||||
uint32_t chip_ver = CHIPID->CHIPID_CIDR & CHIPID_CIDR_VERSION_Msk;
|
||||
|
||||
PMC_EnablePeripheral(ID_ADC);
|
||||
|
||||
ADC->ADC_CR |= ADC_CR_SWRST;
|
||||
if (chip_ver == 0 &&
|
||||
(chip_arch == CHIPID_CIDR_ARCH_SAM3SxA ||
|
||||
chip_arch == CHIPID_CIDR_ARCH_SAM3SxB ||
|
||||
chip_arch == CHIPID_CIDR_ARCH_SAM3SxC)) {
|
||||
TRACE_INFO("Enabling Rev.A ADC Errata work-around\r\n");
|
||||
adc_sam3s_reva_errata = 1;
|
||||
}
|
||||
|
||||
if (adc_sam3s_reva_errata) {
|
||||
/* Errata Work-Around to clear EOCx flags */
|
||||
volatile uint32_t foo;
|
||||
int i;
|
||||
for (i = 0; i < 16; i++)
|
||||
foo = ADC->ADC_CDR[i];
|
||||
}
|
||||
|
||||
/* Initialize ADC for AD7 / AD6, fADC=48/24=2MHz */
|
||||
ADC->ADC_MR = ADC_MR_TRGEN_DIS | ADC_MR_LOWRES_BITS_12 |
|
||||
ADC_MR_SLEEP_NORMAL | ADC_MR_FWUP_OFF |
|
||||
ADC_MR_FREERUN_OFF | ADC_MR_PRESCAL(23) |
|
||||
ADC_MR_STARTUP_SUT8 | ADC_MR_SETTLING(3) |
|
||||
ADC_MR_ANACH_NONE | ADC_MR_TRACKTIM(4) |
|
||||
ADC_MR_TRANSFER(1) | ADC_MR_USEQ_NUM_ORDER;
|
||||
/* enable AD6 + AD7 channels */
|
||||
ADC->ADC_CHER = ADC_CHER_CH7;
|
||||
ADC->ADC_IER = ADC_IER_EOC7;
|
||||
#ifdef CARDEMU_SECOND_UART
|
||||
ADC->ADC_CHER |= ADC_CHER_CH6;
|
||||
ADC->ADC_IER |= ADC_IER_EOC6;
|
||||
#endif
|
||||
NVIC_EnableIRQ(ADC_IRQn);
|
||||
ADC->ADC_CR |= ADC_CR_START;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define UV_PER_LSB ((3300 * 1000) / 4096)
|
||||
#define VCC_UV_THRESH_1V8 1500000
|
||||
#define VCC_UV_THRESH_3V 2800000
|
||||
|
||||
static void process_vcc_adc(struct cardem_inst *ci)
|
||||
{
|
||||
if (ci->vcc_uv >= VCC_UV_THRESH_3V &&
|
||||
ci->vcc_uv_last < VCC_UV_THRESH_3V) {
|
||||
card_emu_io_statechg(ci->ch, CARD_IO_VCC, 1);
|
||||
/* FIXME do this for real */
|
||||
card_emu_io_statechg(ci->ch, CARD_IO_CLK, 1);
|
||||
} else if (ci->vcc_uv < VCC_UV_THRESH_3V &&
|
||||
ci->vcc_uv_last >= VCC_UV_THRESH_3V) {
|
||||
/* FIXME do this for real */
|
||||
card_emu_io_statechg(ci->ch, CARD_IO_CLK, 0);
|
||||
card_emu_io_statechg(ci->ch, CARD_IO_VCC, 0);
|
||||
}
|
||||
ci->vcc_uv_last = ci->vcc_uv;
|
||||
}
|
||||
|
||||
static uint32_t adc2uv(uint16_t adc)
|
||||
{
|
||||
uint32_t uv = (uint32_t) adc * UV_PER_LSB;
|
||||
return uv;
|
||||
}
|
||||
|
||||
void ADC_IrqHandler(void)
|
||||
{
|
||||
#ifdef CARDEMU_SECOND_UART
|
||||
if (ADC->ADC_ISR & ADC_ISR_EOC6) {
|
||||
uint16_t val = ADC->ADC_CDR[6] & 0xFFF;
|
||||
cardem_inst[1].vcc_uv = adc2uv(val);
|
||||
process_vcc_adc(&cardem_inst[1]);
|
||||
if (adc_sam3s_reva_errata) {
|
||||
/* Errata: START doesn't start a conversion
|
||||
* sequence, but only a single conversion */
|
||||
ADC->ADC_CR |= ADC_CR_START;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ADC->ADC_ISR & ADC_ISR_EOC7) {
|
||||
uint16_t val = ADC->ADC_CDR[7] & 0xFFF;
|
||||
cardem_inst[0].vcc_uv = adc2uv(val);
|
||||
process_vcc_adc(&cardem_inst[0]);
|
||||
ADC->ADC_CR |= ADC_CR_START;
|
||||
}
|
||||
}
|
||||
#endif /* DETECT_VCC_BY_ADC */
|
||||
|
||||
/***********************************************************************
|
||||
* Core USB / mainloop integration
|
||||
***********************************************************************/
|
||||
|
||||
static void usim1_rst_irqhandler(const Pin *pPin)
|
||||
{
|
||||
int active = PIO_Get(&pin_usim1_rst) ? 0 : 1;
|
||||
card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_RST, active);
|
||||
}
|
||||
|
||||
#ifndef DETECT_VCC_BY_ADC
|
||||
static void usim1_vcc_irqhandler(const Pin *pPin)
|
||||
{
|
||||
int active = PIO_Get(&pin_usim1_vcc) ? 1 : 0;
|
||||
card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_VCC, active);
|
||||
/* FIXME do this for real */
|
||||
card_emu_io_statechg(cardem_inst[0].ch, CARD_IO_CLK, active);
|
||||
}
|
||||
#endif /* !DETECT_VCC_BY_ADC */
|
||||
|
||||
#ifdef CARDEMU_SECOND_UART
|
||||
static void usim2_rst_irqhandler(const Pin *pPin)
|
||||
{
|
||||
int active = PIO_Get(&pin_usim2_rst) ? 0 : 1;
|
||||
card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_RST, active);
|
||||
}
|
||||
|
||||
#ifndef DETECT_VCC_BY_ADC
|
||||
static void usim2_vcc_irqhandler(const Pin *pPin)
|
||||
{
|
||||
int active = PIO_Get(&pin_usim2_vcc) ? 1 : 0;
|
||||
card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_VCC, active);
|
||||
/* FIXME do this for real */
|
||||
card_emu_io_statechg(cardem_inst[1].ch, CARD_IO_CLK, active);
|
||||
}
|
||||
#endif /* !DETECT_VCC_BY_ADC */
|
||||
#endif /* CARDEMU_SECOND_UART */
|
||||
|
||||
/* executed once at system boot for each config */
|
||||
void mode_cardemu_configure(void)
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
}
|
||||
|
||||
/* called if config is activated */
|
||||
void mode_cardemu_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
TRACE_ENTRY();
|
||||
|
||||
PIO_Configure(pins_cardsim, PIO_LISTSIZE(pins_cardsim));
|
||||
#ifdef DETECT_VCC_BY_ADC
|
||||
card_vcc_adc_init();
|
||||
#endif /* DETECT_VCC_BY_ADC */
|
||||
|
||||
INIT_LLIST_HEAD(&cardem_inst[0].usb_out_queue);
|
||||
rbuf_reset(&cardem_inst[0].rb);
|
||||
PIO_Configure(pins_usim1, PIO_LISTSIZE(pins_usim1));
|
||||
ISO7816_Init(&cardem_inst[0].usart_info, CLK_SLAVE);
|
||||
NVIC_EnableIRQ(USART1_IRQn);
|
||||
PIO_ConfigureIt(&pin_usim1_rst, usim1_rst_irqhandler);
|
||||
PIO_EnableIt(&pin_usim1_rst);
|
||||
#ifndef DETECT_VCC_BY_ADC
|
||||
PIO_ConfigureIt(&pin_usim1_vcc, usim1_vcc_irqhandler);
|
||||
PIO_EnableIt(&pin_usim1_vcc);
|
||||
#endif /* DETECT_VCC_BY_ADC */
|
||||
cardem_inst[0].ch = card_emu_init(0, 2, 0);
|
||||
|
||||
#ifdef CARDEMU_SECOND_UART
|
||||
INIT_LLIST_HEAD(&cardem_inst[1].usb_out_queue);
|
||||
rbuf_reset(&cardem_inst[1].rb);
|
||||
PIO_Configure(pins_usim2, PIO_LISTSIZE(pins_usim2));
|
||||
ISO7816_Init(&cardem_inst[1].usart_info, CLK_SLAVE);
|
||||
NVIC_EnableIRQ(USART0_IRQn);
|
||||
PIO_ConfigureIt(&pin_usim2_rst, usim2_rst_irqhandler);
|
||||
PIO_EnableIt(&pin_usim2_rst);
|
||||
#ifndef DETECT_VCC_BY_ADC
|
||||
PIO_ConfigureIt(&pin_usim2_vcc, usim2_vcc_irqhandler);
|
||||
PIO_EnableIt(&pin_usim2_vcc);
|
||||
#endif /* DETECT_VCC_BY_ADC */
|
||||
cardem_inst[1].ch = card_emu_init(1, 0, 1);
|
||||
#endif /* CARDEMU_SECOND_UART */
|
||||
}
|
||||
|
||||
/* called if config is deactivated */
|
||||
void mode_cardemu_exit(void)
|
||||
{
|
||||
TRACE_ENTRY();
|
||||
|
||||
/* FIXME: stop tc_fdt */
|
||||
/* FIXME: release all rctx, unlink them from any queue */
|
||||
|
||||
PIO_DisableIt(&pin_usim1_rst);
|
||||
PIO_DisableIt(&pin_usim1_vcc);
|
||||
|
||||
NVIC_DisableIRQ(USART1_IRQn);
|
||||
USART_SetTransmitterEnabled(USART1, 0);
|
||||
USART_SetReceiverEnabled(USART1, 0);
|
||||
|
||||
#ifdef CARDEMU_SECOND_UART
|
||||
PIO_DisableIt(&pin_usim2_rst);
|
||||
PIO_DisableIt(&pin_usim2_vcc);
|
||||
|
||||
NVIC_DisableIRQ(USART0_IRQn);
|
||||
USART_SetTransmitterEnabled(USART0, 0);
|
||||
USART_SetReceiverEnabled(USART0, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* handle a single USB command as received from the USB host */
|
||||
static void dispatch_usb_command(struct req_ctx *rctx, struct cardem_inst *ci)
|
||||
{
|
||||
struct cardemu_usb_msg_hdr *hdr;
|
||||
struct cardemu_usb_msg_set_atr *atr;
|
||||
struct cardemu_usb_msg_cardinsert *cardins;
|
||||
struct llist_head *queue;
|
||||
|
||||
hdr = (struct cardemu_usb_msg_hdr *) rctx->data;
|
||||
switch (hdr->msg_type) {
|
||||
case CEMU_USB_MSGT_DT_TX_DATA:
|
||||
queue = card_emu_get_uart_tx_queue(ci->ch);
|
||||
req_ctx_set_state(rctx, RCTX_S_UART_TX_PENDING);
|
||||
llist_add_tail(&rctx->list, queue);
|
||||
card_emu_have_new_uart_tx(ci->ch);
|
||||
break;
|
||||
case CEMU_USB_MSGT_DT_SET_ATR:
|
||||
atr = (struct cardemu_usb_msg_set_atr *) hdr;
|
||||
card_emu_set_atr(ci->ch, atr->atr, atr->atr_len);
|
||||
req_ctx_put(rctx);
|
||||
break;
|
||||
case CEMU_USB_MSGT_DT_CARDINSERT:
|
||||
cardins = (struct cardemu_usb_msg_cardinsert *) hdr;
|
||||
TRACE_INFO("%u: set card_insert to %s\r\n", ci->num,
|
||||
cardins->card_insert ? "INSERTED" : "REMOVED");
|
||||
if (cardins->card_insert)
|
||||
PIO_Set(&ci->pin_insert);
|
||||
else
|
||||
PIO_Clear(&ci->pin_insert);
|
||||
req_ctx_put(rctx);
|
||||
break;
|
||||
case CEMU_USB_MSGT_DT_GET_STATUS:
|
||||
card_emu_report_status(ci->ch);
|
||||
break;
|
||||
case CEMU_USB_MSGT_DT_GET_STATS:
|
||||
default:
|
||||
/* FIXME */
|
||||
req_ctx_put(rctx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void dispatch_received_rctx(struct req_ctx *rctx, struct cardem_inst *ci)
|
||||
{
|
||||
struct req_ctx *segm;
|
||||
struct cardemu_usb_msg_hdr *mh;
|
||||
int i = 0;
|
||||
|
||||
/* check if we have multiple concatenated commands in
|
||||
* one message. USB endpoints are streams that don't
|
||||
* preserve the message boundaries */
|
||||
mh = (struct cardemu_usb_msg_hdr *) rctx->data;
|
||||
if (mh->msg_len == rctx->tot_len) {
|
||||
/* fast path: only one message in buffer */
|
||||
dispatch_usb_command(rctx, ci);
|
||||
return;
|
||||
}
|
||||
|
||||
/* slow path: iterate over list of messages, allocating one new
|
||||
* reqe_ctx per segment */
|
||||
for (mh = (struct cardemu_usb_msg_hdr *) rctx->data;
|
||||
(uint8_t *)mh < rctx->data + rctx->tot_len;
|
||||
mh = (struct cardemu_usb_msg_hdr * ) ((uint8_t *)mh + mh->msg_len)) {
|
||||
segm = req_ctx_find_get(0, RCTX_S_FREE, RCTX_S_MAIN_PROCESSING);
|
||||
if (!segm) {
|
||||
TRACE_ERROR("%u: ENOMEM during rctx segmentation\r\n",
|
||||
ci->num);
|
||||
break;
|
||||
}
|
||||
segm->idx = 0;
|
||||
segm->tot_len = mh->msg_len;
|
||||
memcpy(segm->data, mh, segm->tot_len);
|
||||
dispatch_usb_command(segm, ci);
|
||||
i++;
|
||||
}
|
||||
|
||||
/* release the master req_ctx, as all segments have been
|
||||
* processed now */
|
||||
req_ctx_put(rctx);
|
||||
}
|
||||
|
||||
/* iterate over the queue of incoming USB commands and dispatch/execute
|
||||
* them */
|
||||
static void process_any_usb_commands(struct llist_head *main_q,
|
||||
struct cardem_inst *ci)
|
||||
{
|
||||
struct llist_head *lh;
|
||||
struct req_ctx *rctx;
|
||||
int i;
|
||||
|
||||
/* limit the number of iterations to 10, to ensure we don't get
|
||||
* stuck here without returning to main loop processing */
|
||||
for (i = 0; i < 10; i++) {
|
||||
/* de-queue the list head in an irq-safe way */
|
||||
lh = llist_head_dequeue_irqsafe(main_q);
|
||||
if (!lh)
|
||||
break;
|
||||
rctx = llist_entry(lh, struct req_ctx, list);
|
||||
dispatch_received_rctx(rctx, ci);
|
||||
}
|
||||
}
|
||||
|
||||
/* main loop function, called repeatedly */
|
||||
void mode_cardemu_run(void)
|
||||
{
|
||||
struct llist_head *queue;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cardem_inst); i++) {
|
||||
struct cardem_inst *ci = &cardem_inst[i];
|
||||
|
||||
/* drain the ring buffer from UART into card_emu */
|
||||
while (1) {
|
||||
__disable_irq();
|
||||
if (rbuf_is_empty(&ci->rb)) {
|
||||
__enable_irq();
|
||||
break;
|
||||
}
|
||||
uint8_t byte = rbuf_read(&ci->rb);
|
||||
__enable_irq();
|
||||
card_emu_process_rx_byte(ci->ch, byte);
|
||||
//TRACE_ERROR("%uRx%02x\r\n", i, byte);
|
||||
}
|
||||
|
||||
queue = card_emu_get_usb_tx_queue(ci->ch);
|
||||
int usb_pending = llist_count(queue);
|
||||
if (usb_pending != ci->usb_pending_old) {
|
||||
TRACE_DEBUG("%u usb_pending=%d\r\n",
|
||||
i, usb_pending);
|
||||
ci->usb_pending_old = usb_pending;
|
||||
}
|
||||
usb_refill_to_host(queue, ci->ep_in);
|
||||
|
||||
/* ensure we can handle incoming USB messages from the
|
||||
* host */
|
||||
queue = &ci->usb_out_queue;
|
||||
usb_refill_from_host(queue, ci->ep_out);
|
||||
process_any_usb_commands(queue, ci);
|
||||
}
|
||||
}
|
||||
196
firmware/libcommon/source/phone.c
Normal file
196
firmware/libcommon/source/phone.c
Normal file
@@ -0,0 +1,196 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2009, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Headers
|
||||
*------------------------------------------------------------------------------*/
|
||||
|
||||
#include "board.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Internal definitions
|
||||
*------------------------------------------------------------------------------*/
|
||||
|
||||
/** Maximum ucSize in bytes of the smartcard answer to a command.*/
|
||||
#define MAX_ANSWER_SIZE 10
|
||||
|
||||
/** Maximum ATR ucSize in bytes.*/
|
||||
#define MAX_ATR_SIZE 55
|
||||
|
||||
/** USB states */
|
||||
/// Use for power management
|
||||
#define STATE_IDLE 0
|
||||
/// The USB device is in suspend state
|
||||
#define STATE_SUSPEND 4
|
||||
/// The USB device is in resume state
|
||||
#define STATE_RESUME 5
|
||||
|
||||
extern volatile uint8_t timeout_occured;
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Internal variables
|
||||
*------------------------------------------------------------------------------*/
|
||||
/** USB state: suspend, resume, idle */
|
||||
unsigned char USBState = STATE_IDLE;
|
||||
|
||||
/** ISO7816 pins */
|
||||
static const Pin pinsISO7816_PHONE[] = { PINS_ISO7816_PHONE };
|
||||
|
||||
/** Bus switch pins */
|
||||
|
||||
#if DEBUG_PHONE_SNIFF
|
||||
#warning "Debug phone sniff via logic analyzer is enabled"
|
||||
// Logic analyzer probes are easier to attach to the SIM card slot
|
||||
static const Pin pins_bus[] = { PINS_BUS_SNIFF };
|
||||
#else
|
||||
static const Pin pins_bus[] = { PINS_BUS_DEFAULT };
|
||||
#endif
|
||||
|
||||
/** ISO7816 RST pin */
|
||||
static uint8_t sim_inserted = 0;
|
||||
|
||||
static const Pin pPwr[] = {
|
||||
/* Enable power converter 4.5-6V to 3.3V; low: off */
|
||||
{SIM_PWEN, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT},
|
||||
|
||||
/* Enable second power converter: VCC_PHONE to VCC_SIM; high: off */
|
||||
{VCC_FWD, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT}
|
||||
};
|
||||
|
||||
const Pin pinPhoneRST = PIN_ISO7816_RST_PHONE;
|
||||
|
||||
static struct Usart_info usart_info = {
|
||||
.base = USART_PHONE,
|
||||
.id = ID_USART_PHONE,
|
||||
.state = USART_RCV,
|
||||
};
|
||||
|
||||
/* ===================================================*/
|
||||
/* Taken from iso7816_4.c */
|
||||
/* ===================================================*/
|
||||
/** Flip flop for send and receive char */
|
||||
#define USART_SEND 0
|
||||
#define USART_RCV 1
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Internal variables
|
||||
*-----------------------------------------------------------------------------*/
|
||||
static uint8_t host_to_sim_buf[BUFLEN];
|
||||
static bool change_fidi = false;
|
||||
|
||||
static void receive_from_host(void);
|
||||
static void sendResponse_to_phone(uint8_t * pArg, uint8_t status,
|
||||
uint32_t transferred, uint32_t remaining)
|
||||
{
|
||||
if (status != USBD_STATUS_SUCCESS) {
|
||||
TRACE_ERROR("USB err status: %d (%s)\n", __FUNCTION__, status);
|
||||
return;
|
||||
}
|
||||
TRACE_DEBUG("sendResp, stat: %X, trnsf: %x, rem: %x\n\r", status,
|
||||
transferred, remaining);
|
||||
TRACE_DEBUG("Resp: %x %x %x .. %x\n", host_to_sim_buf[0],
|
||||
host_to_sim_buf[1], host_to_sim_buf[2],
|
||||
host_to_sim_buf[transferred - 1]);
|
||||
|
||||
USART_SetReceiverEnabled(USART_PHONE, 0);
|
||||
USART_SetTransmitterEnabled(USART_PHONE, 1);
|
||||
uint32_t i = 0;
|
||||
if (host_to_sim_buf[0] == 0xff) {
|
||||
printf("Change FIDI detected\n");
|
||||
// PTS command, change FIDI after command
|
||||
i = 2;
|
||||
change_fidi = true;
|
||||
}
|
||||
for (; i < transferred; i++) {
|
||||
ISO7816_SendChar(host_to_sim_buf[i], &usart_info);
|
||||
}
|
||||
USART_SetTransmitterEnabled(USART_PHONE, 0);
|
||||
USART_SetReceiverEnabled(USART_PHONE, 1);
|
||||
|
||||
if (change_fidi == true) {
|
||||
printf("Change FIDI: %x\n", host_to_sim_buf[2]);
|
||||
update_fidi(host_to_sim_buf[2]);
|
||||
change_fidi = false;
|
||||
}
|
||||
|
||||
receive_from_host();
|
||||
}
|
||||
|
||||
static void receive_from_host()
|
||||
{
|
||||
int ret;
|
||||
if ((ret = USBD_Read(PHONE_DATAOUT, &host_to_sim_buf,
|
||||
sizeof(host_to_sim_buf),
|
||||
(TransferCallback) &sendResponse_to_phone,
|
||||
0)) == USBD_STATUS_SUCCESS) {
|
||||
} else {
|
||||
TRACE_ERROR("USB Err: %X\n", ret);
|
||||
}
|
||||
}
|
||||
|
||||
void Phone_configure(void)
|
||||
{
|
||||
PIO_ConfigureIt(&pinPhoneRST, ISR_PhoneRST);
|
||||
NVIC_EnableIRQ(PIOA_IRQn);
|
||||
}
|
||||
|
||||
void Phone_exit(void)
|
||||
{
|
||||
PIO_DisableIt(&pinPhoneRST);
|
||||
NVIC_DisableIRQ(USART1_IRQn);
|
||||
USART_DisableIt(USART_PHONE, US_IER_RXRDY);
|
||||
USART_SetTransmitterEnabled(USART_PHONE, 0);
|
||||
USART_SetReceiverEnabled(USART_PHONE, 0);
|
||||
}
|
||||
|
||||
void Phone_init(void)
|
||||
{
|
||||
PIO_Configure(pinsISO7816_PHONE, PIO_LISTSIZE(pinsISO7816_PHONE));
|
||||
PIO_Configure(pins_bus, PIO_LISTSIZE(pins_bus));
|
||||
|
||||
PIO_Configure(&pinPhoneRST, 1);
|
||||
|
||||
PIO_EnableIt(&pinPhoneRST);
|
||||
ISO7816_Init(&usart_info, CLK_SLAVE);
|
||||
|
||||
USART_SetTransmitterEnabled(USART_PHONE, 0);
|
||||
USART_SetReceiverEnabled(USART_PHONE, 1);
|
||||
|
||||
USART_EnableIt(USART_PHONE, US_IER_RXRDY);
|
||||
NVIC_EnableIRQ(USART1_IRQn);
|
||||
|
||||
receive_from_host();
|
||||
}
|
||||
|
||||
void Phone_run(void)
|
||||
{
|
||||
check_data_from_phone();
|
||||
}
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "chip.h"
|
||||
#include "utils.h"
|
||||
#include "trace.h"
|
||||
#include "req_ctx.h"
|
||||
|
||||
135
firmware/libcommon/source/simtrace_iso7816.c
Normal file
135
firmware/libcommon/source/simtrace_iso7816.c
Normal file
@@ -0,0 +1,135 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2009, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Headers
|
||||
*------------------------------------------------------------------------------*/
|
||||
|
||||
#include "board.h"
|
||||
#include "simtrace.h"
|
||||
#include "ringbuffer.h"
|
||||
#include "iso7816_fidi.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
volatile uint32_t char_stat;
|
||||
|
||||
volatile ringbuf sim_rcv_buf = { {0}, 0, 0 };
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Interrupt routines
|
||||
*-----------------------------------------------------------------------------*/
|
||||
static void Callback_PhoneRST_ISR(uint8_t * pArg, uint8_t status,
|
||||
uint32_t transferred, uint32_t remaining)
|
||||
{
|
||||
printf("rstCB\n\r");
|
||||
PIO_EnableIt(&pinPhoneRST);
|
||||
}
|
||||
|
||||
void ISR_PhoneRST(const Pin * pPin)
|
||||
{
|
||||
int ret;
|
||||
// FIXME: no printfs in ISRs?
|
||||
printf("+++ Int!! %x\n\r", pinPhoneRST.pio->PIO_ISR);
|
||||
if (((pinPhoneRST.pio->PIO_ISR & pinPhoneRST.mask) != 0)) {
|
||||
if (PIO_Get(&pinPhoneRST) == 0) {
|
||||
printf(" 0 ");
|
||||
} else {
|
||||
printf(" 1 ");
|
||||
}
|
||||
}
|
||||
|
||||
if ((ret =
|
||||
USBD_Write(PHONE_INT, "R", 1,
|
||||
(TransferCallback) & Callback_PhoneRST_ISR,
|
||||
0)) != USBD_STATUS_SUCCESS) {
|
||||
TRACE_ERROR("USB err status: %d (%s)\n", ret, __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Interrupt enabled after ATR is sent to phone */
|
||||
PIO_DisableIt(&pinPhoneRST);
|
||||
}
|
||||
|
||||
/*
|
||||
* char_stat is zero if no error occured.
|
||||
* Otherwise it is filled with the content of the status register.
|
||||
*/
|
||||
void mode_trace_usart1_irq(void)
|
||||
{
|
||||
uint32_t stat;
|
||||
char_stat = 0;
|
||||
// Rcv buf full
|
||||
/* if((stat & US_CSR_RXBUFF) == US_CSR_RXBUFF) {
|
||||
TRACE_DEBUG("Rcv buf full");
|
||||
USART_DisableIt(USART1, US_IDR_RXBUFF);
|
||||
}
|
||||
*/
|
||||
uint32_t csr = USART_PHONE->US_CSR;
|
||||
|
||||
if (csr & US_CSR_TXRDY) {
|
||||
/* transmit buffer empty, nothing to transmit */
|
||||
}
|
||||
if (csr & US_CSR_RXRDY) {
|
||||
stat = (csr & (US_CSR_OVRE | US_CSR_FRAME |
|
||||
US_CSR_PARE | US_CSR_TIMEOUT | US_CSR_NACK |
|
||||
(1 << 10)));
|
||||
uint8_t c = (USART_PHONE->US_RHR) & 0xFF;
|
||||
// printf(" %x", c);
|
||||
|
||||
if (stat == 0) {
|
||||
/* Fill char into buffer */
|
||||
rbuf_write(&sim_rcv_buf, c);
|
||||
} else {
|
||||
TRACE_DEBUG("e %x st: %x\n", c, stat);
|
||||
} /* else: error occured */
|
||||
|
||||
char_stat = stat;
|
||||
}
|
||||
}
|
||||
|
||||
/* FIDI update functions */
|
||||
void update_fidi(uint8_t fidi)
|
||||
{
|
||||
int rc;
|
||||
|
||||
uint8_t fi = fidi >> 4;
|
||||
uint8_t di = fidi & 0xf;
|
||||
|
||||
rc = compute_fidi_ratio(fi, di);
|
||||
if (rc > 0 && rc < 0x400) {
|
||||
TRACE_INFO("computed Fi(%u) Di(%u) ratio: %d", fi, di, rc);
|
||||
/* make sure UART uses new F/D ratio */
|
||||
USART_PHONE->US_CR |= US_CR_RXDIS | US_CR_RSTRX;
|
||||
USART_PHONE->US_FIDI = rc & 0x3ff;
|
||||
USART_PHONE->US_CR |= US_CR_RXEN | US_CR_STTTO;
|
||||
} else
|
||||
TRACE_INFO("computed FiDi ratio %d unsupported", rc);
|
||||
}
|
||||
107
firmware/libcommon/source/sniffer.c
Normal file
107
firmware/libcommon/source/sniffer.c
Normal file
@@ -0,0 +1,107 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2009, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifdef HAVE_SNIFFER
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Headers
|
||||
*------------------------------------------------------------------------------*/
|
||||
|
||||
#include "board.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Internal definitions
|
||||
*------------------------------------------------------------------------------*/
|
||||
|
||||
/** Maximum ucSize in bytes of the smartcard answer to a command.*/
|
||||
#define MAX_ANSWER_SIZE 10
|
||||
|
||||
/** Maximum ATR ucSize in bytes.*/
|
||||
#define MAX_ATR_SIZE 55
|
||||
/*------------------------------------------------------------------------------
|
||||
* Internal variables
|
||||
*------------------------------------------------------------------------------*/
|
||||
/** ISO7816 pins */
|
||||
static const Pin pinsISO7816_sniff[] = { PINS_SIM_SNIFF_SIM };
|
||||
static const Pin pins_bus[] = { PINS_BUS_SNIFF };
|
||||
|
||||
static const Pin pPwr[] = {
|
||||
/* Enable power converter 4.5-6V to 3.3V; low: off */
|
||||
{SIM_PWEN, PIOA, ID_PIOA, PIO_OUTPUT_0, PIO_DEFAULT},
|
||||
|
||||
/* Enable second power converter: VCC_PHONE to VCC_SIM; high: on */
|
||||
{VCC_FWD, PIOA, ID_PIOA, PIO_OUTPUT_1, PIO_DEFAULT}
|
||||
};
|
||||
|
||||
static struct Usart_info usart_info = {
|
||||
.base = USART_PHONE,
|
||||
.id = ID_USART_PHONE,
|
||||
.state = USART_RCV,
|
||||
};
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Initialization routine
|
||||
*-----------------------------------------------------------------------------*/
|
||||
|
||||
void Sniffer_configure(void)
|
||||
{
|
||||
TRACE_INFO("Sniffer config\n");
|
||||
}
|
||||
|
||||
void Sniffer_exit(void)
|
||||
{
|
||||
TRACE_INFO("Sniffer exit\n");
|
||||
USART_DisableIt(USART_PHONE, US_IER_RXRDY);
|
||||
NVIC_DisableIRQ(USART1_IRQn);
|
||||
USART_SetReceiverEnabled(USART_PHONE, 0);
|
||||
}
|
||||
|
||||
void Sniffer_init(void)
|
||||
{
|
||||
TRACE_INFO("Sniffer Init\n");
|
||||
/* Configure ISO7816 driver */
|
||||
PIO_Configure(pinsISO7816_sniff, PIO_LISTSIZE(pinsISO7816_sniff));
|
||||
PIO_Configure(pins_bus, PIO_LISTSIZE(pins_bus));
|
||||
|
||||
PIO_Configure(pPwr, PIO_LISTSIZE(pPwr));
|
||||
|
||||
ISO7816_Init(&usart_info, CLK_SLAVE);
|
||||
|
||||
USART_SetReceiverEnabled(USART_PHONE, 1);
|
||||
USART_EnableIt(USART_PHONE, US_IER_RXRDY);
|
||||
NVIC_EnableIRQ(USART1_IRQn);
|
||||
}
|
||||
|
||||
void Sniffer_run(void)
|
||||
{
|
||||
check_data_from_phone();
|
||||
}
|
||||
#endif /* HAVE_SNIFFER */
|
||||
210
firmware/libcommon/source/tc_etu.c
Normal file
210
firmware/libcommon/source/tc_etu.c
Normal file
@@ -0,0 +1,210 @@
|
||||
/* SIMtrace TC (Timer / Clock) code for ETU tracking */
|
||||
|
||||
/* (C) 2006-2016 by Harald Welte <hwelte@hmw-consulting.de>
|
||||
*
|
||||
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "tc_etu.h"
|
||||
|
||||
#include "chip.h"
|
||||
|
||||
/* pins for Channel 0 of TC-block 0 */
|
||||
#define PIN_TCLK0 {PIO_PA4, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT }
|
||||
#define PIN_TIOA0 {PIO_PA0, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
|
||||
#define PIN_TIOB0 {PIO_PA1, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
|
||||
static const Pin pins_tc0[] = { PIN_TCLK0, PIN_TIOA0, PIN_TIOB0 };
|
||||
|
||||
/* pins for Channel 2 of TC-block 0 */
|
||||
#define PIN_TCLK2 {PIO_PA29, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
|
||||
#define PIN_TIOA2 {PIO_PA26, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
|
||||
#define PIN_TIOB2 {PIO_PA27, PIOA, ID_PIOA, PIO_PERIPH_B, PIO_DEFAULT}
|
||||
static const Pin pins_tc2[] = { PIN_TCLK2, PIN_TIOA2, PIN_TIOB2 };
|
||||
|
||||
struct tc_etu_state {
|
||||
/* total negotiated waiting time (default = 9600) */
|
||||
uint16_t waiting_time;
|
||||
/* how many clock cycles per ETU (default = 372) */
|
||||
uint16_t clocks_per_etu;
|
||||
/* how many ETUs does waiting time correspond ? */
|
||||
uint16_t wait_events;
|
||||
/* how many ETUs have we seen expire so far? */
|
||||
uint16_t nr_events;
|
||||
/* channel number */
|
||||
uint8_t chan_nr;
|
||||
/* Timer/Counter register pointer */
|
||||
TcChannel *chan;
|
||||
/* User reference */
|
||||
void *handle;
|
||||
};
|
||||
|
||||
#define INIT_TE_STATE(n) { \
|
||||
.waiting_time = 9600, \
|
||||
.clocks_per_etu = 372, \
|
||||
.wait_events = 10, \
|
||||
.nr_events = 0, \
|
||||
.chan_nr = n, \
|
||||
}
|
||||
|
||||
static struct tc_etu_state te_state0 = INIT_TE_STATE(0);
|
||||
static struct tc_etu_state te_state2 = INIT_TE_STATE(2);
|
||||
|
||||
static struct tc_etu_state *get_te(uint8_t chan_nr)
|
||||
{
|
||||
if (chan_nr == 0)
|
||||
return &te_state0;
|
||||
else
|
||||
return &te_state2;
|
||||
}
|
||||
|
||||
static void tc_etu_irq(struct tc_etu_state *te)
|
||||
{
|
||||
uint32_t sr = te->chan->TC_SR;
|
||||
|
||||
if (sr & TC_SR_ETRGS) {
|
||||
/* external trigger, i.e. we have seen a bit on I/O */
|
||||
te->nr_events = 0;
|
||||
}
|
||||
|
||||
if (sr & TC_SR_CPCS) {
|
||||
/* Compare C event has occurred, i.e. 1 ETU expired */
|
||||
te->nr_events++;
|
||||
if (te->nr_events == te->wait_events/2) {
|
||||
/* Indicate that half the waiting tim has expired */
|
||||
tc_etu_wtime_half_expired(te->handle);
|
||||
}
|
||||
if (te->nr_events >= te->wait_events) {
|
||||
TcChannel *chan = te->chan;
|
||||
chan->TC_CMR |= TC_CMR_ENETRG;
|
||||
|
||||
/* disable and re-enable clock to make it stop */
|
||||
chan->TC_CCR = TC_CCR_CLKDIS;
|
||||
chan->TC_CCR = TC_CCR_CLKEN;
|
||||
|
||||
/* Indicate that the waiting tim has expired */
|
||||
tc_etu_wtime_expired(te->handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TC0_IrqHandler(void)
|
||||
{
|
||||
tc_etu_irq(&te_state0);
|
||||
}
|
||||
|
||||
void TC2_IrqHandler(void)
|
||||
{
|
||||
tc_etu_irq(&te_state2);
|
||||
}
|
||||
|
||||
static void recalc_nr_events(struct tc_etu_state *te)
|
||||
{
|
||||
te->wait_events = te->waiting_time / 12;
|
||||
te->chan->TC_RC = te->clocks_per_etu * 12;
|
||||
}
|
||||
|
||||
void tc_etu_set_wtime(uint8_t chan_nr, uint16_t wtime)
|
||||
{
|
||||
struct tc_etu_state *te = get_te(chan_nr);
|
||||
te->waiting_time = wtime;
|
||||
recalc_nr_events(te);
|
||||
}
|
||||
|
||||
void tc_etu_set_etu(uint8_t chan_nr, uint16_t etu)
|
||||
{
|
||||
struct tc_etu_state *te = get_te(chan_nr);
|
||||
te->clocks_per_etu = etu;
|
||||
recalc_nr_events(te);
|
||||
}
|
||||
|
||||
void tc_etu_enable(uint8_t chan_nr)
|
||||
{
|
||||
struct tc_etu_state *te = get_te(chan_nr);
|
||||
|
||||
te->nr_events = 0;
|
||||
te->chan->TC_CCR = TC_CCR_CLKEN|TC_CCR_SWTRG;
|
||||
}
|
||||
|
||||
void tc_etu_disable(uint8_t chan_nr)
|
||||
{
|
||||
struct tc_etu_state *te = get_te(chan_nr);
|
||||
|
||||
te->nr_events = 0;
|
||||
te->chan->TC_CCR = TC_CCR_CLKDIS;
|
||||
}
|
||||
|
||||
void tc_etu_init(uint8_t chan_nr, void *handle)
|
||||
{
|
||||
struct tc_etu_state *te = get_te(chan_nr);
|
||||
uint32_t tc_clks;
|
||||
|
||||
te->handle = handle;
|
||||
|
||||
switch (chan_nr) {
|
||||
case 0:
|
||||
/* Configure PA4(TCLK0), PA0(TIOA0), PA1(TIB0) */
|
||||
PIO_Configure(pins_tc0, ARRAY_SIZE(pins_tc0));
|
||||
PMC_EnablePeripheral(ID_TC0);
|
||||
/* route TCLK0 to XC2 */
|
||||
TC0->TC_BMR &= ~TC_BMR_TC0XC0S_Msk;
|
||||
TC0->TC_BMR |= TC_BMR_TC0XC0S_TCLK0;
|
||||
tc_clks = TC_CMR_TCCLKS_XC0;
|
||||
/* register interrupt handler */
|
||||
NVIC_EnableIRQ(TC0_IRQn);
|
||||
|
||||
te->chan = &TC0->TC_CHANNEL[0];
|
||||
break;
|
||||
case 2:
|
||||
/* Configure PA29(TCLK2), PA26(TIOA2), PA27(TIOB2) */
|
||||
PIO_Configure(pins_tc2, ARRAY_SIZE(pins_tc2));
|
||||
PMC_EnablePeripheral(ID_TC2);
|
||||
/* route TCLK2 to XC2. TC0 really means TCA in this case */
|
||||
TC0->TC_BMR &= ~TC_BMR_TC2XC2S_Msk;
|
||||
TC0->TC_BMR |= TC_BMR_TC2XC2S_TCLK2;
|
||||
tc_clks = TC_CMR_TCCLKS_XC2;
|
||||
/* register interrupt handler */
|
||||
NVIC_EnableIRQ(TC2_IRQn);
|
||||
|
||||
te->chan = &TC0->TC_CHANNEL[2];
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
/* enable interrupts for Compare-C and external trigger */
|
||||
te->chan->TC_IER = TC_IER_CPCS | TC_IER_ETRGS;
|
||||
|
||||
te->chan->TC_CMR = tc_clks | /* XC(TCLK) clock */
|
||||
TC_CMR_WAVE | /* wave mode */
|
||||
TC_CMR_ETRGEDG_FALLING | /* ext trig on falling edge */
|
||||
TC_CMR_EEVT_TIOB | /* ext trig is TIOB0 */
|
||||
TC_CMR_ENETRG | /* enable ext trig */
|
||||
TC_CMR_WAVSEL_UP_RC | /* wave mode up */
|
||||
TC_CMR_ACPA_SET | /* set TIOA on a compare */
|
||||
TC_CMR_ACPC_CLEAR | /* clear TIOA on C compare */
|
||||
TC_CMR_ASWTRG_CLEAR; /* Clear TIOA on sw trig */
|
||||
|
||||
tc_etu_set_etu(chan_nr, 372);
|
||||
|
||||
/* start with a disabled clock */
|
||||
tc_etu_disable(chan_nr);
|
||||
|
||||
/* Reset to start timers */
|
||||
TC0->TC_BCR = TC_BCR_SYNC;
|
||||
}
|
||||
829
firmware/libcommon/source/usb.c
Normal file
829
firmware/libcommon/source/usb.c
Normal file
@@ -0,0 +1,829 @@
|
||||
/* ----------------------------------------------------------------------------
|
||||
* ATMEL Microcontroller Software Support
|
||||
* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2009, Atmel Corporation
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the disclaimer below.
|
||||
*
|
||||
* Atmel's name may not be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* Headers
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "board.h"
|
||||
#include "simtrace.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <cciddriverdescriptors.h>
|
||||
#include <usb/common/dfu/usb_dfu.h>
|
||||
#include <usb/device/dfu/dfu.h>
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* USB String descriptors
|
||||
*------------------------------------------------------------------------------*/
|
||||
|
||||
static const unsigned char langDesc[] = {
|
||||
|
||||
USBStringDescriptor_LENGTH(1),
|
||||
USBGenericDescriptor_STRING,
|
||||
USBStringDescriptor_ENGLISH_US
|
||||
};
|
||||
|
||||
const unsigned char manufStringDescriptor[] = {
|
||||
|
||||
USBStringDescriptor_LENGTH(24),
|
||||
USBGenericDescriptor_STRING,
|
||||
USBStringDescriptor_UNICODE('s'),
|
||||
USBStringDescriptor_UNICODE('y'),
|
||||
USBStringDescriptor_UNICODE('s'),
|
||||
USBStringDescriptor_UNICODE('m'),
|
||||
USBStringDescriptor_UNICODE('o'),
|
||||
USBStringDescriptor_UNICODE('c'),
|
||||
USBStringDescriptor_UNICODE('o'),
|
||||
USBStringDescriptor_UNICODE('m'),
|
||||
USBStringDescriptor_UNICODE(' '),
|
||||
USBStringDescriptor_UNICODE('-'),
|
||||
USBStringDescriptor_UNICODE(' '),
|
||||
USBStringDescriptor_UNICODE('s'),
|
||||
USBStringDescriptor_UNICODE('.'),
|
||||
USBStringDescriptor_UNICODE('f'),
|
||||
USBStringDescriptor_UNICODE('.'),
|
||||
USBStringDescriptor_UNICODE('m'),
|
||||
USBStringDescriptor_UNICODE('.'),
|
||||
USBStringDescriptor_UNICODE('c'),
|
||||
USBStringDescriptor_UNICODE('.'),
|
||||
USBStringDescriptor_UNICODE(' '),
|
||||
USBStringDescriptor_UNICODE('G'),
|
||||
USBStringDescriptor_UNICODE('m'),
|
||||
USBStringDescriptor_UNICODE('b'),
|
||||
USBStringDescriptor_UNICODE('H'),
|
||||
};
|
||||
|
||||
const unsigned char productStringDescriptor[] = {
|
||||
|
||||
USBStringDescriptor_LENGTH(10),
|
||||
USBGenericDescriptor_STRING,
|
||||
USBStringDescriptor_UNICODE('S'),
|
||||
USBStringDescriptor_UNICODE('I'),
|
||||
USBStringDescriptor_UNICODE('M'),
|
||||
USBStringDescriptor_UNICODE('t'),
|
||||
USBStringDescriptor_UNICODE('r'),
|
||||
USBStringDescriptor_UNICODE('a'),
|
||||
USBStringDescriptor_UNICODE('c'),
|
||||
USBStringDescriptor_UNICODE('e'),
|
||||
USBStringDescriptor_UNICODE(' '),
|
||||
USBStringDescriptor_UNICODE('2'),
|
||||
};
|
||||
|
||||
const unsigned char snifferConfigStringDescriptor[] = {
|
||||
|
||||
USBStringDescriptor_LENGTH(16),
|
||||
USBGenericDescriptor_STRING,
|
||||
USBStringDescriptor_UNICODE('S'),
|
||||
USBStringDescriptor_UNICODE('I'),
|
||||
USBStringDescriptor_UNICODE('M'),
|
||||
USBStringDescriptor_UNICODE('t'),
|
||||
USBStringDescriptor_UNICODE('r'),
|
||||
USBStringDescriptor_UNICODE('a'),
|
||||
USBStringDescriptor_UNICODE('c'),
|
||||
USBStringDescriptor_UNICODE('e'),
|
||||
USBStringDescriptor_UNICODE(' '),
|
||||
USBStringDescriptor_UNICODE('S'),
|
||||
USBStringDescriptor_UNICODE('n'),
|
||||
USBStringDescriptor_UNICODE('i'),
|
||||
USBStringDescriptor_UNICODE('f'),
|
||||
USBStringDescriptor_UNICODE('f'),
|
||||
USBStringDescriptor_UNICODE('e'),
|
||||
USBStringDescriptor_UNICODE('r'),
|
||||
};
|
||||
|
||||
const unsigned char CCIDConfigStringDescriptor[] = {
|
||||
|
||||
USBStringDescriptor_LENGTH(13),
|
||||
USBGenericDescriptor_STRING,
|
||||
USBStringDescriptor_UNICODE('S'),
|
||||
USBStringDescriptor_UNICODE('I'),
|
||||
USBStringDescriptor_UNICODE('M'),
|
||||
USBStringDescriptor_UNICODE('t'),
|
||||
USBStringDescriptor_UNICODE('r'),
|
||||
USBStringDescriptor_UNICODE('a'),
|
||||
USBStringDescriptor_UNICODE('c'),
|
||||
USBStringDescriptor_UNICODE('e'),
|
||||
USBStringDescriptor_UNICODE(' '),
|
||||
USBStringDescriptor_UNICODE('C'),
|
||||
USBStringDescriptor_UNICODE('C'),
|
||||
USBStringDescriptor_UNICODE('I'),
|
||||
USBStringDescriptor_UNICODE('D'),
|
||||
};
|
||||
|
||||
const unsigned char phoneConfigStringDescriptor[] = {
|
||||
|
||||
USBStringDescriptor_LENGTH(14),
|
||||
USBGenericDescriptor_STRING,
|
||||
USBStringDescriptor_UNICODE('S'),
|
||||
USBStringDescriptor_UNICODE('I'),
|
||||
USBStringDescriptor_UNICODE('M'),
|
||||
USBStringDescriptor_UNICODE('t'),
|
||||
USBStringDescriptor_UNICODE('r'),
|
||||
USBStringDescriptor_UNICODE('a'),
|
||||
USBStringDescriptor_UNICODE('c'),
|
||||
USBStringDescriptor_UNICODE('e'),
|
||||
USBStringDescriptor_UNICODE(' '),
|
||||
USBStringDescriptor_UNICODE('P'),
|
||||
USBStringDescriptor_UNICODE('h'),
|
||||
USBStringDescriptor_UNICODE('o'),
|
||||
USBStringDescriptor_UNICODE('n'),
|
||||
USBStringDescriptor_UNICODE('e'),
|
||||
};
|
||||
|
||||
const unsigned char MITMConfigStringDescriptor[] = {
|
||||
|
||||
USBStringDescriptor_LENGTH(13),
|
||||
USBGenericDescriptor_STRING,
|
||||
USBStringDescriptor_UNICODE('S'),
|
||||
USBStringDescriptor_UNICODE('I'),
|
||||
USBStringDescriptor_UNICODE('M'),
|
||||
USBStringDescriptor_UNICODE('t'),
|
||||
USBStringDescriptor_UNICODE('r'),
|
||||
USBStringDescriptor_UNICODE('a'),
|
||||
USBStringDescriptor_UNICODE('c'),
|
||||
USBStringDescriptor_UNICODE('e'),
|
||||
USBStringDescriptor_UNICODE(' '),
|
||||
USBStringDescriptor_UNICODE('M'),
|
||||
USBStringDescriptor_UNICODE('I'),
|
||||
USBStringDescriptor_UNICODE('T'),
|
||||
USBStringDescriptor_UNICODE('M'),
|
||||
};
|
||||
|
||||
const unsigned char cardem_usim1_intf_str[] = {
|
||||
|
||||
USBStringDescriptor_LENGTH(18),
|
||||
USBGenericDescriptor_STRING,
|
||||
USBStringDescriptor_UNICODE('C'),
|
||||
USBStringDescriptor_UNICODE('a'),
|
||||
USBStringDescriptor_UNICODE('r'),
|
||||
USBStringDescriptor_UNICODE('d'),
|
||||
USBStringDescriptor_UNICODE('E'),
|
||||
USBStringDescriptor_UNICODE('m'),
|
||||
USBStringDescriptor_UNICODE('u'),
|
||||
USBStringDescriptor_UNICODE('l'),
|
||||
USBStringDescriptor_UNICODE('a'),
|
||||
USBStringDescriptor_UNICODE('t'),
|
||||
USBStringDescriptor_UNICODE('o'),
|
||||
USBStringDescriptor_UNICODE('r'),
|
||||
USBStringDescriptor_UNICODE(' '),
|
||||
USBStringDescriptor_UNICODE('U'),
|
||||
USBStringDescriptor_UNICODE('S'),
|
||||
USBStringDescriptor_UNICODE('I'),
|
||||
USBStringDescriptor_UNICODE('M'),
|
||||
USBStringDescriptor_UNICODE('1'),
|
||||
};
|
||||
|
||||
const unsigned char cardem_usim2_intf_str[] = {
|
||||
|
||||
USBStringDescriptor_LENGTH(18),
|
||||
USBGenericDescriptor_STRING,
|
||||
USBStringDescriptor_UNICODE('C'),
|
||||
USBStringDescriptor_UNICODE('a'),
|
||||
USBStringDescriptor_UNICODE('r'),
|
||||
USBStringDescriptor_UNICODE('d'),
|
||||
USBStringDescriptor_UNICODE('E'),
|
||||
USBStringDescriptor_UNICODE('m'),
|
||||
USBStringDescriptor_UNICODE('u'),
|
||||
USBStringDescriptor_UNICODE('l'),
|
||||
USBStringDescriptor_UNICODE('a'),
|
||||
USBStringDescriptor_UNICODE('t'),
|
||||
USBStringDescriptor_UNICODE('o'),
|
||||
USBStringDescriptor_UNICODE('r'),
|
||||
USBStringDescriptor_UNICODE(' '),
|
||||
USBStringDescriptor_UNICODE('U'),
|
||||
USBStringDescriptor_UNICODE('S'),
|
||||
USBStringDescriptor_UNICODE('I'),
|
||||
USBStringDescriptor_UNICODE('M'),
|
||||
USBStringDescriptor_UNICODE('2'),
|
||||
};
|
||||
|
||||
enum strDescNum {
|
||||
PRODUCT_STRING = 1,
|
||||
MANUF_STR,
|
||||
SNIFFER_CONF_STR,
|
||||
CCID_CONF_STR,
|
||||
PHONE_CONF_STR,
|
||||
MITM_CONF_STR,
|
||||
CARDEM_USIM1_INTF_STR,
|
||||
CARDEM_USIM2_INTF_STR,
|
||||
STRING_DESC_CNT
|
||||
};
|
||||
|
||||
/** List of string descriptors used by the device */
|
||||
static const unsigned char *stringDescriptors[] = {
|
||||
langDesc,
|
||||
[PRODUCT_STRING] = productStringDescriptor,
|
||||
[MANUF_STR] = manufStringDescriptor,
|
||||
[SNIFFER_CONF_STR] = snifferConfigStringDescriptor,
|
||||
[CCID_CONF_STR] = CCIDConfigStringDescriptor,
|
||||
[PHONE_CONF_STR] = phoneConfigStringDescriptor,
|
||||
[MITM_CONF_STR] = MITMConfigStringDescriptor,
|
||||
[CARDEM_USIM1_INTF_STR] = cardem_usim1_intf_str,
|
||||
[CARDEM_USIM2_INTF_STR] = cardem_usim2_intf_str,
|
||||
};
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* USB Device descriptors
|
||||
*------------------------------------------------------------------------------*/
|
||||
|
||||
#ifdef HAVE_SNIFFER
|
||||
typedef struct _SIMTraceDriverConfigurationDescriptorSniffer {
|
||||
|
||||
/** Standard configuration descriptor. */
|
||||
USBConfigurationDescriptor configuration;
|
||||
USBInterfaceDescriptor sniffer;
|
||||
USBEndpointDescriptor sniffer_dataOut;
|
||||
USBEndpointDescriptor sniffer_dataIn;
|
||||
USBEndpointDescriptor sniffer_interruptIn;
|
||||
DFURT_IF_DESCRIPTOR_STRUCT;
|
||||
} __attribute__ ((packed)) SIMTraceDriverConfigurationDescriptorSniffer;
|
||||
|
||||
static const SIMTraceDriverConfigurationDescriptorSniffer
|
||||
configurationDescriptorSniffer = {
|
||||
/* Standard configuration descriptor */
|
||||
{
|
||||
.bLength = sizeof(USBConfigurationDescriptor),
|
||||
.bDescriptorType = USBGenericDescriptor_CONFIGURATION,
|
||||
.wTotalLength = sizeof(SIMTraceDriverConfigurationDescriptorSniffer),
|
||||
.bNumInterfaces = 1+DFURT_NUM_IF,
|
||||
.bConfigurationValue = CFG_NUM_SNIFF,
|
||||
.iConfiguration = SNIFFER_CONF_STR,
|
||||
.bmAttributes = USBD_BMATTRIBUTES,
|
||||
.bMaxPower = USBConfigurationDescriptor_POWER(100),
|
||||
},
|
||||
/* Communication class interface standard descriptor */
|
||||
{
|
||||
.bLength = sizeof(USBInterfaceDescriptor),
|
||||
.bDescriptorType = USBGenericDescriptor_INTERFACE,
|
||||
.bInterfaceNumber = 0,
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 3,
|
||||
.bInterfaceClass = 0xff,
|
||||
.bInterfaceSubClass = 0,
|
||||
.bInterfaceProtocol = 0,
|
||||
.iInterface = SNIFFER_CONF_STR,
|
||||
},
|
||||
/* Bulk-OUT endpoint standard descriptor */
|
||||
{
|
||||
.bLength = sizeof(USBEndpointDescriptor),
|
||||
.bDescriptorType = USBGenericDescriptor_ENDPOINT,
|
||||
.bEndpointAddress = USBEndpointDescriptor_ADDRESS(
|
||||
USBEndpointDescriptor_OUT,
|
||||
PHONE_DATAOUT),
|
||||
.bmAttributes = USBEndpointDescriptor_BULK,
|
||||
.wMaxPacketSize = MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(
|
||||
PHONE_DATAOUT),
|
||||
USBEndpointDescriptor_MAXBULKSIZE_FS),
|
||||
.bInterval = 0,
|
||||
},
|
||||
/* Bulk-IN endpoint descriptor */
|
||||
{
|
||||
.bLength = sizeof(USBEndpointDescriptor),
|
||||
.bDescriptorType = USBGenericDescriptor_ENDPOINT,
|
||||
.bEndpointAddress = USBEndpointDescriptor_ADDRESS(
|
||||
USBEndpointDescriptor_IN,
|
||||
PHONE_DATAIN),
|
||||
.bmAttributes = USBEndpointDescriptor_BULK,
|
||||
.wMaxPacketSize = MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(
|
||||
PHONE_DATAIN),
|
||||
USBEndpointDescriptor_MAXBULKSIZE_FS),
|
||||
.bInterval = 0,
|
||||
},
|
||||
// Notification endpoint descriptor
|
||||
{
|
||||
.bLength = sizeof(USBEndpointDescriptor),
|
||||
.bDescriptorType = USBGenericDescriptor_ENDPOINT,
|
||||
.bEndpointAddress = USBEndpointDescriptor_ADDRESS(
|
||||
USBEndpointDescriptor_IN,
|
||||
PHONE_INT),
|
||||
.bmAttributes = USBEndpointDescriptor_INTERRUPT,
|
||||
.wMaxPacketSize = MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(
|
||||
PHONE_INT),
|
||||
USBEndpointDescriptor_MAXINTERRUPTSIZE_FS),
|
||||
.bInterval = 0x10,
|
||||
},
|
||||
DFURT_IF_DESCRIPTOR(1, 0),
|
||||
};
|
||||
#endif /* HAVE_SNIFFER */
|
||||
|
||||
#ifdef HAVE_CCID
|
||||
static const CCIDDriverConfigurationDescriptors configurationDescriptorCCID = {
|
||||
// Standard USB configuration descriptor
|
||||
{
|
||||
.bLength = sizeof(USBConfigurationDescriptor),
|
||||
.bDescriptorType = USBGenericDescriptor_CONFIGURATION,
|
||||
.wTotalLength = sizeof(CCIDDriverConfigurationDescriptors),
|
||||
.bNumInterfaces = 1+DFURT_NUM_IF,
|
||||
.bConfigurationValue = CFG_NUM_CCID,
|
||||
.iConfiguration = CCID_CONF_STR,
|
||||
.bmAttributes = BOARD_USB_BMATTRIBUTES,
|
||||
.bMaxPower = USBConfigurationDescriptor_POWER(100),
|
||||
},
|
||||
// CCID interface descriptor
|
||||
// Table 4.3-1 Interface Descriptor
|
||||
// Interface descriptor
|
||||
{
|
||||
.bLength = sizeof(USBInterfaceDescriptor),
|
||||
.bDescriptorType = USBGenericDescriptor_INTERFACE,
|
||||
.bInterfaceNumber = 0,
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 3,
|
||||
.bInterfaceClass = SMART_CARD_DEVICE_CLASS,
|
||||
.bInterfaceSubClass = 0,
|
||||
.bInterfaceProtocol = 0,
|
||||
.iInterface = CCID_CONF_STR,
|
||||
},
|
||||
{
|
||||
.bLength = sizeof(CCIDDescriptor),
|
||||
.bDescriptorType = CCID_DECRIPTOR_TYPE,
|
||||
.bcdCCID = CCID1_10, // CCID version
|
||||
.bMaxSlotIndex = 0, // 1 slot
|
||||
.bVoltageSupport = VOLTS_3_0,
|
||||
.dwProtocols = (1 << PROTOCOL_TO),
|
||||
.dwDefaultClock = 3580,
|
||||
.dwMaximumClock = 3580,
|
||||
.bNumClockSupported = 0,
|
||||
.dwDataRate = 9600,
|
||||
.dwMaxDataRate = 9600,
|
||||
.bNumDataRatesSupported = 0,
|
||||
.dwMaxIFSD = 0xfe,
|
||||
.dwSynchProtocols = 0,
|
||||
.dwMechanical = 0,
|
||||
.dwFeatures = CCID_FEATURES_AUTO_CLOCK | CCID_FEATURES_AUTO_BAUD |
|
||||
CCID_FEATURES_AUTO_PCONF | CCID_FEATURES_AUTO_PNEGO |
|
||||
CCID_FEATURES_EXC_TPDU,
|
||||
.dwMaxCCIDMessageLength = 271, /* For extended APDU
|
||||
level the value shall
|
||||
be between 261 + 10 */
|
||||
.bClassGetResponse = 0xFF, // Echoes the class of the APDU
|
||||
.bClassEnvelope = 0xFF, // Echoes the class of the APDU
|
||||
.wLcdLayout = 0, // wLcdLayout: no LCD
|
||||
.bPINSupport = 0, // bPINSupport: No PIN
|
||||
.bMaxCCIDBusySlots = 1,
|
||||
},
|
||||
// Bulk-OUT endpoint descriptor
|
||||
{
|
||||
.bLength = sizeof(USBEndpointDescriptor),
|
||||
.bDescriptorType = USBGenericDescriptor_ENDPOINT,
|
||||
.bEndpointAddress =
|
||||
USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_OUT,
|
||||
CCID_EPT_DATA_OUT),
|
||||
.bmAttributes = USBEndpointDescriptor_BULK,
|
||||
.wMaxPacketSize = MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(
|
||||
CCID_EPT_DATA_OUT),
|
||||
USBEndpointDescriptor_MAXBULKSIZE_FS),
|
||||
.bInterval = 0x00,
|
||||
},
|
||||
// Bulk-IN endpoint descriptor
|
||||
{
|
||||
.bLength = sizeof(USBEndpointDescriptor),
|
||||
.bDescriptorType = USBGenericDescriptor_ENDPOINT,
|
||||
.bEndpointAddress =
|
||||
USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN,
|
||||
CCID_EPT_DATA_IN),
|
||||
.bmAttributes = USBEndpointDescriptor_BULK,
|
||||
.wMaxPacketSize = MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(
|
||||
CCID_EPT_DATA_IN),
|
||||
USBEndpointDescriptor_MAXBULKSIZE_FS),
|
||||
.bInterval = 0x00,
|
||||
},
|
||||
// Notification endpoint descriptor
|
||||
{
|
||||
.bLength = sizeof(USBEndpointDescriptor),
|
||||
.bDescriptorType = USBGenericDescriptor_ENDPOINT,
|
||||
.bEndpointAddress =
|
||||
USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN,
|
||||
CCID_EPT_NOTIFICATION),
|
||||
.bmAttributes = USBEndpointDescriptor_INTERRUPT,
|
||||
.wMaxPacketSize = MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(
|
||||
CCID_EPT_NOTIFICATION),
|
||||
USBEndpointDescriptor_MAXINTERRUPTSIZE_FS),
|
||||
.bInterval = 0x10,
|
||||
},
|
||||
DFURT_IF_DESCRIPTOR(1, 0),
|
||||
};
|
||||
#endif /* HAVE_CCID */
|
||||
|
||||
#ifdef HAVE_CARDEM
|
||||
/* SIM card emulator */
|
||||
typedef struct _SIMTraceDriverConfigurationDescriptorPhone {
|
||||
/* Standard configuration descriptor. */
|
||||
USBConfigurationDescriptor configuration;
|
||||
USBInterfaceDescriptor phone;
|
||||
USBEndpointDescriptor phone_dataOut;
|
||||
USBEndpointDescriptor phone_dataIn;
|
||||
USBEndpointDescriptor phone_interruptIn;
|
||||
#ifdef CARDEMU_SECOND_UART
|
||||
USBInterfaceDescriptor usim2;
|
||||
USBEndpointDescriptor usim2_dataOut;
|
||||
USBEndpointDescriptor usim2_dataIn;
|
||||
USBEndpointDescriptor usim2_interruptIn;
|
||||
#endif
|
||||
DFURT_IF_DESCRIPTOR_STRUCT;
|
||||
} __attribute__ ((packed)) SIMTraceDriverConfigurationDescriptorPhone;
|
||||
|
||||
static const SIMTraceDriverConfigurationDescriptorPhone
|
||||
configurationDescriptorPhone = {
|
||||
/* Standard configuration descriptor */
|
||||
{
|
||||
sizeof(USBConfigurationDescriptor),
|
||||
USBGenericDescriptor_CONFIGURATION,
|
||||
sizeof(SIMTraceDriverConfigurationDescriptorPhone),
|
||||
#ifdef CARDEMU_SECOND_UART
|
||||
2+DFURT_NUM_IF,
|
||||
#else
|
||||
1+DFURT_NUM_IF, /* There is one interface in this configuration */
|
||||
#endif
|
||||
CFG_NUM_PHONE, /* configuration number */
|
||||
PHONE_CONF_STR, /* string descriptor for this configuration */
|
||||
USBD_BMATTRIBUTES,
|
||||
USBConfigurationDescriptor_POWER(100)
|
||||
},
|
||||
/* Communication class interface standard descriptor */
|
||||
{
|
||||
sizeof(USBInterfaceDescriptor),
|
||||
USBGenericDescriptor_INTERFACE,
|
||||
0, /* This is interface #0 */
|
||||
0, /* This is alternate setting #0 for this interface */
|
||||
3, /* Number of endpoints */
|
||||
0xff, /* Descriptor Class: Vendor specific */
|
||||
0, /* No subclass */
|
||||
0, /* No l */
|
||||
CARDEM_USIM1_INTF_STR
|
||||
},
|
||||
/* Bulk-OUT endpoint standard descriptor */
|
||||
{
|
||||
sizeof(USBEndpointDescriptor),
|
||||
USBGenericDescriptor_ENDPOINT,
|
||||
USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_OUT,
|
||||
PHONE_DATAOUT),
|
||||
USBEndpointDescriptor_BULK,
|
||||
MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(PHONE_DATAOUT),
|
||||
USBEndpointDescriptor_MAXBULKSIZE_FS),
|
||||
0 /* Must be 0 for full-speed bulk endpoints */
|
||||
},
|
||||
/* Bulk-IN endpoint descriptor */
|
||||
{
|
||||
sizeof(USBEndpointDescriptor),
|
||||
USBGenericDescriptor_ENDPOINT,
|
||||
USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN,
|
||||
PHONE_DATAIN),
|
||||
USBEndpointDescriptor_BULK,
|
||||
MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(PHONE_DATAIN),
|
||||
USBEndpointDescriptor_MAXBULKSIZE_FS),
|
||||
0 /* Must be 0 for full-speed bulk endpoints */
|
||||
},
|
||||
/* Notification endpoint descriptor */
|
||||
{
|
||||
sizeof(USBEndpointDescriptor),
|
||||
USBGenericDescriptor_ENDPOINT,
|
||||
USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN,
|
||||
PHONE_INT),
|
||||
USBEndpointDescriptor_INTERRUPT,
|
||||
MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(PHONE_INT),
|
||||
USBEndpointDescriptor_MAXINTERRUPTSIZE_FS),
|
||||
0x10
|
||||
},
|
||||
#ifdef CARDEMU_SECOND_UART
|
||||
/* Communication class interface standard descriptor */
|
||||
{
|
||||
sizeof(USBInterfaceDescriptor),
|
||||
USBGenericDescriptor_INTERFACE,
|
||||
1, /* This is interface #1 */
|
||||
0, /* This is alternate setting #0 for this interface */
|
||||
3, /* Number of endpoints */
|
||||
0xff, /* Descriptor Class: Vendor specific */
|
||||
0, /* No subclass */
|
||||
0, /* No l */
|
||||
CARDEM_USIM2_INTF_STR
|
||||
},
|
||||
/* Bulk-OUT endpoint standard descriptor */
|
||||
{
|
||||
sizeof(USBEndpointDescriptor),
|
||||
USBGenericDescriptor_ENDPOINT,
|
||||
USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_OUT,
|
||||
CARDEM_USIM2_DATAOUT),
|
||||
USBEndpointDescriptor_BULK,
|
||||
MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(CARDEM_USIM2_DATAOUT),
|
||||
USBEndpointDescriptor_MAXBULKSIZE_FS),
|
||||
0 /* Must be 0 for full-speed bulk endpoints */
|
||||
}
|
||||
,
|
||||
/* Bulk-IN endpoint descriptor */
|
||||
{
|
||||
sizeof(USBEndpointDescriptor),
|
||||
USBGenericDescriptor_ENDPOINT,
|
||||
USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN,
|
||||
CARDEM_USIM2_DATAIN),
|
||||
USBEndpointDescriptor_BULK,
|
||||
MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(CARDEM_USIM2_DATAIN),
|
||||
USBEndpointDescriptor_MAXBULKSIZE_FS),
|
||||
0 /* Must be 0 for full-speed bulk endpoints */
|
||||
},
|
||||
/* Notification endpoint descriptor */
|
||||
{
|
||||
sizeof(USBEndpointDescriptor),
|
||||
USBGenericDescriptor_ENDPOINT,
|
||||
USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN,
|
||||
CARDEM_USIM2_INT),
|
||||
USBEndpointDescriptor_INTERRUPT,
|
||||
MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(CARDEM_USIM2_INT),
|
||||
USBEndpointDescriptor_MAXINTERRUPTSIZE_FS),
|
||||
0x10
|
||||
},
|
||||
DFURT_IF_DESCRIPTOR(2, 0),
|
||||
#else
|
||||
DFURT_IF_DESCRIPTOR(1, 0),
|
||||
#endif
|
||||
};
|
||||
#endif /* HAVE_CARDEM */
|
||||
|
||||
#ifdef HAVE_MITM
|
||||
typedef struct _SIMTraceDriverConfigurationDescriptorMITM {
|
||||
/* Standard configuration descriptor. */
|
||||
USBConfigurationDescriptor configuration;
|
||||
USBInterfaceDescriptor simcard;
|
||||
/// CCID descriptor
|
||||
CCIDDescriptor ccid;
|
||||
/// Bulk OUT endpoint descriptor
|
||||
USBEndpointDescriptor simcard_dataOut;
|
||||
/// Bulk IN endpoint descriptor
|
||||
USBEndpointDescriptor simcard_dataIn;
|
||||
/// Interrupt OUT endpoint descriptor
|
||||
USBEndpointDescriptor simcard_interruptIn;
|
||||
|
||||
USBInterfaceDescriptor phone;
|
||||
USBEndpointDescriptor phone_dataOut;
|
||||
USBEndpointDescriptor phone_dataIn;
|
||||
USBEndpointDescriptor phone_interruptIn;
|
||||
|
||||
DFURT_IF_DESCRIPTOR_STRUCT;
|
||||
|
||||
} __attribute__ ((packed)) SIMTraceDriverConfigurationDescriptorMITM;
|
||||
|
||||
static const SIMTraceDriverConfigurationDescriptorMITM
|
||||
configurationDescriptorMITM = {
|
||||
/* Standard configuration descriptor */
|
||||
{
|
||||
sizeof(USBConfigurationDescriptor),
|
||||
USBGenericDescriptor_CONFIGURATION,
|
||||
sizeof(SIMTraceDriverConfigurationDescriptorMITM),
|
||||
2+DFURT_NUM_IF, /* There are two interfaces in this configuration */
|
||||
CFG_NUM_MITM, /* configuration number */
|
||||
MITM_CONF_STR, /* string descriptor for this configuration */
|
||||
USBD_BMATTRIBUTES,
|
||||
USBConfigurationDescriptor_POWER(100)
|
||||
},
|
||||
// CCID interface descriptor
|
||||
// Table 4.3-1 Interface Descriptor
|
||||
// Interface descriptor
|
||||
{
|
||||
.bLength = sizeof(USBInterfaceDescriptor),
|
||||
.bDescriptorType = USBGenericDescriptor_INTERFACE,
|
||||
.bInterfaceNumber = 0,
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 3,
|
||||
.bInterfaceClass = SMART_CARD_DEVICE_CLASS,
|
||||
.bInterfaceSubClass = 0,
|
||||
.bInterfaceProtocol = 0,
|
||||
.iInterface = CCID_CONF_STR,
|
||||
},
|
||||
{
|
||||
.bLength = sizeof(CCIDDescriptor),
|
||||
.bDescriptorType = CCID_DECRIPTOR_TYPE,
|
||||
.bcdCCID = CCID1_10, // CCID version
|
||||
.bMaxSlotIndex = 0, // 1 slot
|
||||
.bVoltageSupport = VOLTS_3_0,
|
||||
.dwProtocols = (1 << PROTOCOL_TO),
|
||||
.dwDefaultClock = 3580,
|
||||
.dwMaximumClock = 3580,
|
||||
.bNumClockSupported = 0,
|
||||
.dwDataRate = 9600,
|
||||
.dwMaxDataRate = 9600,
|
||||
.bNumDataRatesSupported = 0,
|
||||
.dwMaxIFSD = 0xfe,
|
||||
.dwSynchProtocols = 0,
|
||||
.dwMechanical = 0,
|
||||
.dwFeatures = CCID_FEATURES_AUTO_CLOCK | CCID_FEATURES_AUTO_BAUD |
|
||||
CCID_FEATURES_AUTO_PCONF | CCID_FEATURES_AUTO_PNEGO |
|
||||
CCID_FEATURES_EXC_TPDU,
|
||||
.dwMaxCCIDMessageLength = 271, /* For extended APDU
|
||||
level the value shall
|
||||
be between 261 + 10 */
|
||||
.bClassGetResponse = 0xFF, // Echoes the class of the APDU
|
||||
.bClassEnvelope = 0xFF, // Echoes the class of the APDU
|
||||
.wLcdLayout = 0, // wLcdLayout: no LCD
|
||||
.bPINSupport = 0, // bPINSupport: No PIN
|
||||
.bMaxCCIDBusySlots = 1,
|
||||
},
|
||||
// Bulk-OUT endpoint descriptor
|
||||
{
|
||||
.bLength = sizeof(USBEndpointDescriptor),
|
||||
.bDescriptorType = USBGenericDescriptor_ENDPOINT,
|
||||
.bEndpointAddress =
|
||||
USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_OUT,
|
||||
CCID_EPT_DATA_OUT),
|
||||
.bmAttributes = USBEndpointDescriptor_BULK,
|
||||
.wMaxPacketSize = MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(
|
||||
CCID_EPT_DATA_OUT),
|
||||
USBEndpointDescriptor_MAXBULKSIZE_FS),
|
||||
.bInterval = 0x00,
|
||||
},
|
||||
// Bulk-IN endpoint descriptor
|
||||
{
|
||||
.bLength = sizeof(USBEndpointDescriptor),
|
||||
.bDescriptorType = USBGenericDescriptor_ENDPOINT,
|
||||
.bEndpointAddress =
|
||||
USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN,
|
||||
CCID_EPT_DATA_IN),
|
||||
.bmAttributes = USBEndpointDescriptor_BULK,
|
||||
.wMaxPacketSize = MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(
|
||||
CCID_EPT_DATA_IN),
|
||||
USBEndpointDescriptor_MAXBULKSIZE_FS),
|
||||
.bInterval = 0x00,
|
||||
},
|
||||
// Notification endpoint descriptor
|
||||
{
|
||||
.bLength = sizeof(USBEndpointDescriptor),
|
||||
.bDescriptorType = USBGenericDescriptor_ENDPOINT,
|
||||
.bEndpointAddress =
|
||||
USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN,
|
||||
CCID_EPT_NOTIFICATION),
|
||||
.bmAttributes = USBEndpointDescriptor_INTERRUPT,
|
||||
.wMaxPacketSize = MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(
|
||||
CCID_EPT_NOTIFICATION),
|
||||
USBEndpointDescriptor_MAXINTERRUPTSIZE_FS),
|
||||
.bInterval = 0x10,
|
||||
},
|
||||
|
||||
/* Communication class interface standard descriptor */
|
||||
{
|
||||
sizeof(USBInterfaceDescriptor),
|
||||
USBGenericDescriptor_INTERFACE,
|
||||
1, /* This is interface #1 */
|
||||
0, /* This is alternate setting #0 for this interface */
|
||||
3, /* Number of endpoints */
|
||||
0xff,
|
||||
0,
|
||||
0,
|
||||
PHONE_CONF_STR, /* string descriptor for this interface */
|
||||
}
|
||||
,
|
||||
/* Bulk-OUT endpoint standard descriptor */
|
||||
{
|
||||
sizeof(USBEndpointDescriptor),
|
||||
USBGenericDescriptor_ENDPOINT,
|
||||
USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_OUT,
|
||||
PHONE_DATAOUT),
|
||||
USBEndpointDescriptor_BULK,
|
||||
MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(PHONE_DATAOUT),
|
||||
USBEndpointDescriptor_MAXBULKSIZE_FS),
|
||||
0 /* Must be 0 for full-speed bulk endpoints */
|
||||
}
|
||||
,
|
||||
/* Bulk-IN endpoint descriptor */
|
||||
{
|
||||
sizeof(USBEndpointDescriptor),
|
||||
USBGenericDescriptor_ENDPOINT,
|
||||
USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN,
|
||||
PHONE_DATAIN),
|
||||
USBEndpointDescriptor_BULK,
|
||||
MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(PHONE_DATAIN),
|
||||
USBEndpointDescriptor_MAXBULKSIZE_FS),
|
||||
0 /* Must be 0 for full-speed bulk endpoints */
|
||||
}
|
||||
,
|
||||
/* Notification endpoint descriptor */
|
||||
{
|
||||
sizeof(USBEndpointDescriptor),
|
||||
USBGenericDescriptor_ENDPOINT,
|
||||
USBEndpointDescriptor_ADDRESS(USBEndpointDescriptor_IN, PHONE_INT),
|
||||
USBEndpointDescriptor_INTERRUPT,
|
||||
MIN(BOARD_USB_ENDPOINTS_MAXPACKETSIZE(PHONE_INT),
|
||||
USBEndpointDescriptor_MAXINTERRUPTSIZE_FS),
|
||||
0x10},
|
||||
DFURT_IF_DESCRIPTOR(2, 0),
|
||||
};
|
||||
#endif /* HAVE_CARDEM */
|
||||
|
||||
const USBConfigurationDescriptor *configurationDescriptorsArr[] = {
|
||||
#ifdef HAVE_SNIFFER
|
||||
&configurationDescriptorSniffer.configuration,
|
||||
#endif
|
||||
#ifdef HAVE_CCID
|
||||
&configurationDescriptorCCID.configuration,
|
||||
#endif
|
||||
#ifdef HAVE_CARDEM
|
||||
&configurationDescriptorPhone.configuration,
|
||||
#endif
|
||||
#ifdef HAVE_MITM
|
||||
&configurationDescriptorMITM.configuration,
|
||||
#endif
|
||||
};
|
||||
|
||||
/** Standard USB device descriptor for the CDC serial driver */
|
||||
const USBDeviceDescriptor deviceDescriptor = {
|
||||
.bLength = sizeof(USBDeviceDescriptor),
|
||||
.bDescriptorType = USBGenericDescriptor_DEVICE,
|
||||
.bcdUSB = USBDeviceDescriptor_USB2_00,
|
||||
.bDeviceClass = 0xff,
|
||||
.bDeviceSubClass = 0xff,
|
||||
.bDeviceProtocol = 0xff,
|
||||
.bMaxPacketSize0 = BOARD_USB_ENDPOINTS_MAXPACKETSIZE(0),
|
||||
.idVendor = SIMTRACE_VENDOR_ID,
|
||||
.idProduct = SIMTRACE_PRODUCT_ID,
|
||||
.bcdDevice = 2, /* Release number */
|
||||
.iManufacturer = MANUF_STR,
|
||||
.iProduct = PRODUCT_STRING,
|
||||
.iSerialNumber = 0,
|
||||
.bNumConfigurations = ARRAY_SIZE(configurationDescriptorsArr),
|
||||
};
|
||||
|
||||
/* AT91SAM3S only supports full speed, but not high speed USB */
|
||||
static const USBDDriverDescriptors driverDescriptors = {
|
||||
&deviceDescriptor,
|
||||
(const USBConfigurationDescriptor **)&(configurationDescriptorsArr), /* first full-speed configuration descriptor */
|
||||
0, /* No full-speed device qualifier descriptor */
|
||||
0, /* No full-speed other speed configuration */
|
||||
0, /* No high-speed device descriptor */
|
||||
0, /* No high-speed configuration descriptor */
|
||||
0, /* No high-speed device qualifier descriptor */
|
||||
0, /* No high-speed other speed configuration descriptor */
|
||||
stringDescriptors,
|
||||
STRING_DESC_CNT /* cnt string descriptors in list */
|
||||
};
|
||||
|
||||
#if (BOARD_MAINOSC == 12000000)
|
||||
#define PLLB_CFG (CKGR_PLLBR_DIVB(2)|CKGR_PLLBR_MULB(8-1)|CKGR_PLLBR_PLLBCOUNT_Msk)
|
||||
#elif (BOARD_MAINOSC == 18432000)
|
||||
#define PLLB_CFG (CKGR_PLLBR_DIVB(5)|CKGR_PLLBR_MULB(13-1)|CKGR_PLLBR_PLLBCOUNT_Msk)
|
||||
#else
|
||||
#error "Please configure PLLB for your MAINOSC freq"
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* Functions
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* \brief Configure 48MHz Clock for USB
|
||||
*/
|
||||
static void _ConfigureUsbClock(void)
|
||||
{
|
||||
/* Enable PLLB for USB */
|
||||
PMC->CKGR_PLLBR = PLLB_CFG;
|
||||
while ((PMC->PMC_SR & PMC_SR_LOCKB) == 0) ;
|
||||
|
||||
/* USB Clock uses PLLB */
|
||||
PMC->PMC_USB = PMC_USB_USBDIV(0) /* /1 (no divider) */
|
||||
| PMC_USB_USBS; /* PLLB */
|
||||
}
|
||||
|
||||
void SIMtrace_USB_Initialize(void)
|
||||
{
|
||||
_ConfigureUsbClock();
|
||||
// Get std USB driver
|
||||
USBDDriver *pUsbd = USBD_GetDriver();
|
||||
|
||||
TRACE_DEBUG(".");
|
||||
|
||||
// Initialize standard USB driver
|
||||
USBDDriver_Initialize(pUsbd, &driverDescriptors, 0); // Multiple interface settings not supported
|
||||
USBD_Init();
|
||||
USBD_Connect();
|
||||
|
||||
NVIC_EnableIRQ(UDP_IRQn);
|
||||
}
|
||||
|
||||
void USBDCallbacks_RequestReceived(const USBGenericRequest *request)
|
||||
{
|
||||
/* FIXME: integration with CCID control point reqeusts */
|
||||
USBDFU_Runtime_RequestHandler(request);
|
||||
}
|
||||
Reference in New Issue
Block a user