/* This module provides IFD handling functions for Coolstream internal reader. */ #include"../globals.h" #if defined(CARDREADER_INTERNAL_COOLAPI) || defined(CARDREADER_INTERNAL_COOLAPI2) #include "../extapi/coolapi.h" #include "../oscam-string.h" #include "../oscam-time.h" #include "atr.h" #define OK 0 #define ERROR 1 extern int32_t cool_kal_opened; struct cool_data { void *handle; //device handle for coolstream uint8_t cardbuffer[512]; uint32_t cardbuflen; int8_t pps; }; static int32_t Cool_Init(struct s_reader *reader) { char *device = reader->device; int32_t reader_nb = 0; // this is to stay compatible with older config. if(cs_strlen(device)) { reader_nb = atoi((const char *)device); } if(reader_nb > 1) { // there are only 2 readers in the coolstream : 0 or 1 rdr_log(reader, "Coolstream reader device can only be 0 or 1"); return 0; } if(!cs_malloc(&reader->crdr_data, sizeof(struct cool_data))) { return ERROR; } struct cool_data *crdr_data = reader->crdr_data; if(cnxt_smc_open(&crdr_data->handle, &reader_nb, NULL, NULL)) { return 0; } int32_t ret = cnxt_smc_enable_flow_control(crdr_data->handle, 0); coolapi_check_error("cnxt_smc_enable_flow_control", ret); crdr_data->cardbuflen = 0; crdr_data->pps = 0; return OK; } static int32_t Cool_FastReset(struct s_reader *reader) { struct cool_data *crdr_data = reader->crdr_data; int32_t n = ATR_MAX_SIZE, ret; unsigned char buf[ATR_MAX_SIZE]; //reset card ret = cnxt_smc_reset_card(crdr_data->handle, ATR_TIMEOUT, NULL, NULL); coolapi_check_error("cnxt_smc_reset_card", ret); cs_sleepms(50); ret = cnxt_smc_get_atr(crdr_data->handle, buf, &n); coolapi_check_error("cnxt_smc_get_atr", ret); return OK; } static int32_t Cool_SetClockrate(struct s_reader *reader, int32_t mhz) { struct cool_data *crdr_data = reader->crdr_data; uint32_t clk; clk = mhz * 10000; int32_t ret = cnxt_smc_set_clock_freq(crdr_data->handle, clk); coolapi_check_error("cnxt_smc_set_clock_freq", ret); call(Cool_FastReset(reader)); rdr_log_dbg(reader, D_DEVICE, "COOL: clock successfully set to %i", clk); return OK; } static int32_t Cool_GetStatus(struct s_reader *reader, int32_t *in) { struct cool_data *crdr_data = reader->crdr_data; if(cool_kal_opened) { int32_t state; int32_t ret = cnxt_smc_get_state(crdr_data->handle, &state); if(ret) { coolapi_check_error("cnxt_smc_get_state", ret); return ERROR; } //state = 0 no card, 1 = not ready, 2 = ready if(state) { *in = 1; } //CARD, even if not ready report card is in, or it will never get activated else { *in = 0; } //NOCARD } else { *in = 0; } return OK; } static int32_t Cool_Reset(struct s_reader *reader, ATR *atr) { struct cool_data *crdr_data = reader->crdr_data; int32_t ret; if(!reader->ins7e11_fast_reset) { //set freq to reader->cardmhz if necessary uint32_t clk; ret = cnxt_smc_get_clock_freq(crdr_data->handle, &clk); coolapi_check_error("cnxt_smc_get_clock_freq", ret); if(clk / 10000 != (uint32_t)reader->cardmhz) { rdr_log_dbg(reader, D_DEVICE, "COOL: clock freq: %i, scheduling change to %i for card reset", clk, reader->cardmhz * 10000); call(Cool_SetClockrate(reader, reader->cardmhz)); } } else { rdr_log(reader, "Doing fast reset"); } //reset card ret = cnxt_smc_reset_card(crdr_data->handle, ATR_TIMEOUT, NULL, NULL); coolapi_check_error("cnxt_smc_reset_card", ret); cs_sleepms(50); int32_t n = ATR_MAX_SIZE; unsigned char buf[ATR_MAX_SIZE]; ret = cnxt_smc_get_atr(crdr_data->handle, buf, &n); coolapi_check_error("cnxt_smc_get_atr", ret); call(!(ATR_InitFromArray(atr, buf, n) != ERROR)); { cs_sleepms(50); return OK; } } static int32_t Cool_Transmit(struct s_reader *reader, unsigned char *sent, uint32_t size, uint32_t expectedlen, uint32_t UNUSED(delay), uint32_t UNUSED(timeout)) { struct cool_data *crdr_data = reader->crdr_data; int32_t ret; memset(crdr_data->cardbuffer, 0, 512); if(reader->protocol_type == ATR_PROTOCOL_TYPE_T0) { crdr_data->cardbuflen = expectedlen; ret = cnxt_smc_read_write(crdr_data->handle, 0, sent, size, crdr_data->cardbuffer, &crdr_data->cardbuflen, 0, NULL); } else { crdr_data->cardbuflen = 512; ret = cnxt_smc_read_write(crdr_data->handle, 0, sent, size, crdr_data->cardbuffer, &crdr_data->cardbuflen, 4000, NULL); } coolapi_check_error("cnxt_smc_read_write", ret); rdr_log_dump_dbg(reader, D_DEVICE, sent, size, "COOL Transmit:"); if(ret) { return ERROR; } return OK; } static int32_t Cool_Receive(struct s_reader *reader, unsigned char *data, uint32_t size, uint32_t UNUSED(delay), uint32_t UNUSED(timeout)) { struct cool_data *crdr_data = reader->crdr_data; if(size > crdr_data->cardbuflen) { size = crdr_data->cardbuflen; } //never read past end of buffer memcpy(data, crdr_data->cardbuffer, size); crdr_data->cardbuflen -= size; memmove(crdr_data->cardbuffer, crdr_data->cardbuffer + size, crdr_data->cardbuflen); rdr_log_dump_dbg(reader, D_DEVICE, data, size, "COOL Receive:"); return OK; } static void Cool_Print_Comm_Parameters(struct s_reader *reader) { struct cool_data *crdr_data = reader->crdr_data; uint16_t F; uint8_t D; int32_t ret = cnxt_smc_get_F_D_factors(crdr_data->handle, &F, &D); coolapi_check_error("cnxt_smc_get_F_D_factors", ret); char *protocol; CNXT_SMC_COMM comm; ret = cnxt_smc_get_comm_parameters(crdr_data->handle, &comm); coolapi_check_error("cnxt_smc_get_comm_parameters", ret); if(comm.protocol == 0x01) { protocol = "T0"; } else if(comm.protocol == 0x02) { protocol = "T1"; } else if(comm.protocol == 0x04) { protocol = "T14"; } else { protocol = "unknown"; } rdr_log(reader, "Driver Settings: Convention=%s, Protocol=%s, FI=%i, F=%i, N=%i, DI=%i, D=%i, PI1=%i, PI2=%i, II=%i, TXRetries=%i, RXRetries=%i, FilterProtocolBytes=%i", comm.convention ? "Inverse" : "Direct", protocol, comm.FI, F, comm.N, comm.DI, D, comm.PI1, comm.PI2, comm.II, comm.retries.TXRetries, comm.retries.RXRetries, comm.filterprotocolbytes); CNXT_SMC_TIMEOUT timeout; ret = cnxt_smc_get_config_timeout(crdr_data->handle, &timeout); coolapi_check_error("cnxt_smc_get_config_timeout", ret); rdr_log(reader, "Driver Timeouts: CardActTime=%i, CardDeactTime=%i, ATRSTime=%i, ATRDTime=%i, BLKTime=%i, CHTime=%i, CHGuardTime=%i, BKGuardTime=%i", timeout.CardActTime, timeout.CardDeactTime, timeout.ATRSTime, timeout.ATRDTime, timeout.BLKTime, timeout.CHTime, timeout.CHGuardTime, timeout.BKGuardTime); } static int32_t Cool_WriteSettings(struct s_reader *reader, struct s_cardreader_settings *s) { struct cool_data *crdr_data = reader->crdr_data; //first set freq back to reader->mhz if necessary uint32_t clk; int32_t ret = cnxt_smc_get_clock_freq(crdr_data->handle, &clk); coolapi_check_error("cnxt_smc_get_clock_freq", ret); if(clk / 10000 != (uint32_t)reader->mhz) { rdr_log_dbg(reader, D_DEVICE, "COOL: clock freq: %i, scheduling change to %i", clk, reader->mhz * 10000); call(Cool_SetClockrate(reader, reader->mhz)); } uint32_t BLKTime = 0, CHTime = 0; uint8_t BKGuardTime = 0; switch(reader->protocol_type) { case ATR_PROTOCOL_TYPE_T1: if(reader->BWT > 11) { BLKTime = (reader->BWT - 11); } if(reader->CWT > 11) { CHTime = (reader->CWT - 11); } if(s->BGT > 11) { BKGuardTime = (s->BGT - 11); } else { BKGuardTime = 11; } //For T1, the BGT minimum time shall be 22 work etus. BGT is effectively offset by 11 etus internally. if(!crdr_data->pps) { ret = cnxt_smc_set_F_D_factors(crdr_data->handle, s->F, s->D); coolapi_check_error("cnxt_smc_set_F_D_factors", ret); } break; case ATR_PROTOCOL_TYPE_T0: case ATR_PROTOCOL_TYPE_T14: default: BLKTime = 0; if(s->WWT > 12) { CHTime = (s->WWT - 12); } if(s->BGT > 12) { BKGuardTime = (s->BGT - 12); } if(BKGuardTime < 4) { BKGuardTime = 4; } //For T0, the BGT minimum time shall be 16 work etus. BGT is effectively offset by 12 etus internally. if(!crdr_data->pps) { if(reader->protocol_type == ATR_PROTOCOL_TYPE_T14) { ret = cnxt_smc_set_F_D_factors(crdr_data->handle, 620, 1); } else { ret = cnxt_smc_set_F_D_factors(crdr_data->handle, s->F, s->D); } coolapi_check_error("cnxt_smc_set_F_D_factors", ret); } break; } ret = cnxt_smc_set_convention(crdr_data->handle, reader->convention); coolapi_check_error("cnxt_smc_set_convention", ret); CNXT_SMC_TIMEOUT timeout; ret = cnxt_smc_get_config_timeout(crdr_data->handle, &timeout); coolapi_check_error("cnxt_smc_get_config_timeout", ret); timeout.BLKTime = BLKTime; timeout.CHTime = CHTime; timeout.CHGuardTime = s->EGT; timeout.BKGuardTime = BKGuardTime; ret = cnxt_smc_set_config_timeout(crdr_data->handle, timeout); coolapi_check_error("cnxt_smc_set_config_timeout", ret); Cool_Print_Comm_Parameters(reader); return OK; } static int32_t Cool_Close(struct s_reader *reader) { struct cool_data *crdr_data = reader->crdr_data; if(cool_kal_opened) { int32_t ret = cnxt_smc_close(crdr_data->handle); coolapi_check_error("cnxt_smc_close", ret); } return OK; } static int32_t Cool_SetProtocol(struct s_reader *reader, unsigned char *params, uint32_t *UNUSED(length), uint32_t UNUSED(len_request)) { struct cool_data *crdr_data = reader->crdr_data; unsigned char pps[4], response[6]; uint8_t len = 0; //Driver sets PTSS and PCK on its own pps[0] = params[1]; //PPS0 pps[1] = params[2]; //PPS1 int32_t ret = cnxt_smc_start_pps(crdr_data->handle, pps, response, &len, 1); coolapi_check_error("cnxt_smc_start_pps", ret); if(ret) { return ERROR; } crdr_data->pps = 1; return OK; } const struct s_cardreader cardreader_internal_cool = { .desc = "internal", .typ = R_INTERNAL, .max_clock_speed = 1, .reader_init = Cool_Init, .get_status = Cool_GetStatus, .activate = Cool_Reset, .transmit = Cool_Transmit, .receive = Cool_Receive, .close = Cool_Close, .write_settings = Cool_WriteSettings, .set_protocol = Cool_SetProtocol, }; #endif