ccid: Handle IccPowerOn and XfrBlock asynchronously
In real hardware, the CCID code will have to wait for the related UART transfers to complete. Hence, simulate this by starting a timer and responding asynchronously to those commands. Change-Id: I6aa13a3c6e6ea37902c07584174413bfd058dd36
This commit is contained in:
parent
005b09d024
commit
505d4410e0
|
@ -403,14 +403,10 @@ static int ccid_handle_icc_power_on(struct ccid_slot *cs, struct msgb *msg)
|
|||
{
|
||||
const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
|
||||
const struct ccid_header *ch = (const struct ccid_header *) u;
|
||||
uint8_t seq = u->icc_power_on.hdr.bSeq;
|
||||
struct msgb *resp;
|
||||
|
||||
/* TODO: send actual ATR; handle error cases */
|
||||
/* TODO: handle this asynchronously */
|
||||
resp = ccid_gen_data_block(cs, seq, CCID_CMD_STATUS_OK, 0, NULL, 0);
|
||||
|
||||
return ccid_slot_send_unbusy(cs, resp);
|
||||
/* handle this asynchronously */
|
||||
cs->ci->slot_ops->icc_power_on_async(cs, msg, &u->icc_power_on);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Section 6.1.2 */
|
||||
|
@ -431,12 +427,10 @@ static int ccid_handle_xfr_block(struct ccid_slot *cs, struct msgb *msg)
|
|||
{
|
||||
const union ccid_pc_to_rdr *u = msgb_ccid_out(msg);
|
||||
const struct ccid_header *ch = (const struct ccid_header *) u;
|
||||
uint8_t seq = u->xfr_block.hdr.bSeq;
|
||||
struct msgb *resp;
|
||||
|
||||
/* FIXME: handle this asynchronously */
|
||||
resp = ccid_gen_data_block(cs, seq, CCID_CMD_STATUS_OK, 0, NULL, 0);
|
||||
return ccid_slot_send_unbusy(cs, resp);
|
||||
/* handle this asynchronously */
|
||||
cs->ci->slot_ops->xfr_block_async(cs, msg, &u->xfr_block);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Section 6.1.5 */
|
||||
|
|
|
@ -78,6 +78,10 @@ struct ccid_slot_ops {
|
|||
* update the (power/clock/...) status from the hardware */
|
||||
void (*pre_proc_cb)(struct ccid_slot *cs, struct msgb *msg);
|
||||
|
||||
void (*icc_power_on_async)(struct ccid_slot *cs, struct msgb *msg,
|
||||
const struct ccid_pc_to_rdr_icc_power_on *ipo);
|
||||
void (*xfr_block_async)(struct ccid_slot *cs, struct msgb *msg,
|
||||
const struct ccid_pc_to_rdr_xfr_block *xfb);
|
||||
void (*set_power)(struct ccid_slot *cs, bool enable);
|
||||
void (*set_clock)(struct ccid_slot *cs, enum ccid_clock_command cmd);
|
||||
int (*set_params)(struct ccid_slot *cs, enum ccid_protocol_num proto,
|
||||
|
|
|
@ -1,8 +1,30 @@
|
|||
/* Simulated CCID card slot. This is used in absence of a real hardware back-end
|
||||
* in order to test the CCID firmware codebase in a virtual environment */
|
||||
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/core/timer.h>
|
||||
|
||||
#include "ccid_device.h"
|
||||
|
||||
struct slotsim_slot {
|
||||
struct osmo_timer_list pwron_timer;
|
||||
struct osmo_timer_list xfr_timer;
|
||||
/* bSeq of the operation currently in progress */
|
||||
uint8_t seq;
|
||||
};
|
||||
|
||||
struct slotsim_instance {
|
||||
struct slotsim_slot slot[NR_SLOTS];
|
||||
};
|
||||
|
||||
static struct slotsim_instance g_si;
|
||||
|
||||
struct slotsim_slot *ccid_slot2slotsim_slot(struct ccid_slot *cs)
|
||||
{
|
||||
OSMO_ASSERT(cs->slot_nr < ARRAY_SIZE(g_si.slot));
|
||||
return &g_si.slot[cs->slot_nr];
|
||||
}
|
||||
|
||||
static const struct ccid_pars_decoded slotsim_def_pars = {
|
||||
.fi = 0,
|
||||
.di = 0,
|
||||
|
@ -20,6 +42,47 @@ static void slotsim_pre_proc_cb(struct ccid_slot *cs, struct msgb *msg)
|
|||
/* do nothing; real hardware would update the slot related state here */
|
||||
}
|
||||
|
||||
static void slotsim_icc_power_on_async(struct ccid_slot *cs, struct msgb *msg,
|
||||
const struct ccid_pc_to_rdr_icc_power_on *ipo)
|
||||
{
|
||||
struct slotsim_slot *ss = ccid_slot2slotsim_slot(cs);
|
||||
|
||||
ss->seq = ipo->hdr.bSeq;
|
||||
osmo_timer_schedule(&ss->pwron_timer, 1, 0);
|
||||
msgb_free(msg);
|
||||
/* continues in timer call-back below */
|
||||
}
|
||||
static void slotsim_pwron_timer_cb(void *data)
|
||||
{
|
||||
struct ccid_slot *cs = data;
|
||||
struct slotsim_slot *ss = ccid_slot2slotsim_slot(cs);
|
||||
struct msgb *resp;
|
||||
|
||||
resp = ccid_gen_data_block(cs, ss->seq, CCID_CMD_STATUS_OK, 0, NULL, 0);
|
||||
ccid_slot_send_unbusy(cs, resp);
|
||||
}
|
||||
|
||||
static void slotsim_xfr_block_async(struct ccid_slot *cs, struct msgb *msg,
|
||||
const struct ccid_pc_to_rdr_xfr_block *xfb)
|
||||
{
|
||||
struct slotsim_slot *ss = ccid_slot2slotsim_slot(cs);
|
||||
|
||||
ss->seq = xfb->hdr.bSeq;
|
||||
osmo_timer_schedule(&ss->xfr_timer, 0, 50000);
|
||||
msgb_free(msg);
|
||||
/* continues in timer call-back below */
|
||||
}
|
||||
static void slotsim_xfr_timer_cb(void *data)
|
||||
{
|
||||
struct ccid_slot *cs = data;
|
||||
struct slotsim_slot *ss = ccid_slot2slotsim_slot(cs);
|
||||
struct msgb *resp;
|
||||
|
||||
resp = ccid_gen_data_block(cs, ss->seq, CCID_CMD_STATUS_OK, 0, NULL, 0);
|
||||
ccid_slot_send_unbusy(cs, resp);
|
||||
}
|
||||
|
||||
|
||||
static void slotsim_set_power(struct ccid_slot *cs, bool enable)
|
||||
{
|
||||
if (enable) {
|
||||
|
@ -56,8 +119,12 @@ static int slotsim_set_rate_and_clock(struct ccid_slot *cs, uint32_t freq_hz, ui
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int slotsim_init(struct ccid_slot *cs)
|
||||
{
|
||||
struct slotsim_slot *ss = ccid_slot2slotsim_slot(cs);
|
||||
osmo_timer_setup(&ss->pwron_timer, slotsim_pwron_timer_cb, cs);
|
||||
osmo_timer_setup(&ss->xfr_timer, slotsim_xfr_timer_cb, cs);
|
||||
cs->default_pars = &slotsim_def_pars;
|
||||
return 0;
|
||||
}
|
||||
|
@ -65,6 +132,8 @@ static int slotsim_init(struct ccid_slot *cs)
|
|||
const struct ccid_slot_ops slotsim_slot_ops = {
|
||||
.init = slotsim_init,
|
||||
.pre_proc_cb = slotsim_pre_proc_cb,
|
||||
.icc_power_on_async = slotsim_icc_power_on_async,
|
||||
.xfr_block_async = slotsim_xfr_block_async,
|
||||
.set_power = slotsim_set_power,
|
||||
.set_clock = slotsim_set_clock,
|
||||
.set_params = slotsim_set_params,
|
||||
|
|
Loading…
Reference in New Issue