oscam-2.26.01-11942-802-wit.../csctapi/ifd_sci.c
2026-02-23 17:40:08 +01:00

577 lines
21 KiB
C
Raw Permalink Blame History

/*
ifd_sci.c
This module provides IFD handling functions for SCI internal reader.
*/
#include "../globals.h"
#ifdef CARDREADER_INTERNAL_SCI
#include "../oscam-time.h"
#include "atr.h"
#include "ifd_sci_global.h"
#include "ifd_sci_ioctl.h"
#include "io_serial.h"
#include "../oscam-string.h"
#define OK 0
#define ERROR 1
struct sr_data
{
uint8_t old_reset;
unsigned char T;
uint32_t fs;
uint32_t ETU;
uint32_t WWT;
uint32_t CWT;
uint32_t BWT;
uint32_t EGT;
unsigned char P;
unsigned char I;
};
static int32_t Sci_GetStatus(struct s_reader *reader, int32_t *status)
{
call (ioctl(reader->handle, IOCTL_GET_IS_CARD_PRESENT, status)<0);
return OK;
}
static int32_t Sci_Deactivate(struct s_reader *reader)
{
int32_t in = 0 ;
rdr_log(reader, "Deactivating card");
if (ioctl(reader->handle, IOCTL_GET_IS_CARD_PRESENT, &in)<0)
{
rdr_log(reader, "Error:%s ioctl(IOCTL_GET_IS_CARD_PRESENT) failed.(%d:%s)", __FUNCTION__, errno, strerror(errno) );
return ERROR;
}
if (in != 1) {ioctl(reader->handle, IOCTL_GET_IS_CARD_ACTIVATED, &in);}
if(in && boxtype_is("dm8000"))
{
if((ioctl(reader->handle, IOCTL_SET_DEACTIVATE)<0))
{
rdr_log(reader,"ioctl(IOCTL_SET_DEACTIVATE) not supported on %s", boxtype_get());
return ERROR;
}
}
else {return ERROR;}
return OK;
}
static int32_t Sci_Activate(struct s_reader *reader)
{
rdr_log_dbg(reader, D_IFD, "Is card present?");
int32_t in = 0;
if (ioctl(reader->handle, IOCTL_GET_IS_CARD_PRESENT, &in)<0)
{
rdr_log(reader, "Error:%s ioctl(IOCTL_GET_IS_CARD_PRESENT) failed.(%d:%s)", __FUNCTION__, errno, strerror(errno) );
Sci_Deactivate(reader);
return ERROR;
}
if (in != 1) {ioctl(reader->handle, IOCTL_GET_IS_CARD_ACTIVATED, &in);}
if (in)
{
cs_sleepms(50);
return OK;
}
else
{
rdr_log(reader, "Error: no card is present in readerslot!");
Sci_Deactivate(reader);
return ERROR;
}
}
static int32_t Sci_Read_ATR(struct s_reader *reader, ATR *atr) // reads ATR on the fly: reading and some low levelchecking at the same time
{
uint32_t timeout = ATR_TIMEOUT;
unsigned char buf[SCI_MAX_ATR_SIZE];
int32_t n = 0, statusreturn = 0;
if(IO_Serial_Read(reader, 0, timeout, 1, buf + n)) //read first char of atr
{
rdr_log(reader, "ERROR: no characters found in ATR!");
return ERROR;
}
if(buf[0] == 0x3F) // 3F: card is using inverse convention, 3B = card is using direct convention
{
rdr_log_dbg(reader, D_IFD, "This card uses inverse convention");
}
else { rdr_log_dbg(reader, D_IFD, "This card uses direct convention"); }
n++;
if(IO_Serial_Read(reader, 0, timeout, 1, buf + n))
{
rdr_log_dbg(reader, D_IFD, "ERROR: only 1 character found in ATR");
return ERROR;
}
int32_t T0 = buf[n];
int32_t historicalbytes = T0 & 0x0F; // num of historical bytes in lower nibble of T0 byte
rdr_log_dbg(reader, D_ATR, "ATR historicalbytes should be: %d", historicalbytes);
rdr_log_dbg(reader, D_ATR, "Fetching global interface characters for protocol T0"); // protocol T0 always aboard!
n++;
int32_t protocols = 1, tck = 0, protocol, protocolnumber; // protocols = total protocols on card, tck = checksum byte present, protocol = mandatory protocol
int32_t D = 0; // protocolnumber = TDi uses protocolnumber
int32_t TDi = T0; // place T0 char into TDi for looped parsing.
while(n < SCI_MAX_ATR_SIZE)
{
if(TDi & 0x10) //TA Present: //The value of TA(i) is always interpreted as XI || UI if i > 2 and T = 15 ='F'in TD(i<>1)
{
if(IO_Serial_Read(reader, 0, timeout, 1, buf + n)) { break; } //In this case, TA(i) contains the clock stop indicator XI, which indicates the logical
//state the clockline must assume when the clock is stopped, and the class indicator UI,
rdr_log_dbg(reader, D_ATR, "TA%d: %02X", protocols, buf[n]); //which specifies the supply voltage class.
if((protocols > 2) && ((TDi & 0x0F) == 0x0F)) // Protocol T15 does not exists, it means mandatory on all ATRs
{
if((buf[n] & 0xC0) == 0xC0) { rdr_log_dbg(reader, D_ATR, "Clockline low or high on clockstop"); }
if((buf[n] & 0xC0) == 0x00) { rdr_log_dbg(reader, D_ATR, "Clockline not supported on clockstop"); }
if((buf[n] & 0xC0) == 0x40) { rdr_log_dbg(reader, D_ATR, "Clockline should be low on clockstop"); }
if((buf[n] & 0xC0) == 0x80) { rdr_log_dbg(reader, D_ATR, "Clockline should be high on clockstop"); }
if((buf[n] & 0x3F) == 0x01) { rdr_log_dbg(reader, D_ATR, "Voltage class A 4.5~5.5V"); }
if((buf[n] & 0x3F) == 0x02) { rdr_log_dbg(reader, D_ATR, "Voltage class B 2.7~3.3V"); }
if((buf[n] & 0x3F) == 0x03) { rdr_log_dbg(reader, D_ATR, "Voltage class A 4.5~5.5V and class B 2.7~3.3V"); }
if((buf[n] & 0x3F) == 0x04) { rdr_log_dbg(reader, D_ATR, "Voltage RFU"); }
}
if((protocols > 2) && ((TDi & 0x0F) == 0x01)) // Protocol T1 specfic (There is always an obsolete T0 protocol!)
{
int32_t ifsc = buf[n];
if(ifsc == 0x00) { ifsc = 32; } //default is 32
rdr_log_dbg(reader, D_ATR, "Maximum information field length this card can receive is %d bytes (IFSC)", ifsc);
}
if(protocols < 2)
{
int32_t FI = (buf[n] >> 4); // FI is high nibble ***** work ETU = (1/D)*(Frequencydivider/cardfrequency) (in seconds!)
int32_t Fi = atr_f_table[FI]; // lookup the frequency divider
float fmax = atr_fs_table[FI]; // lookup the max frequency ***** initial ETU = 372 / initial frequency during atr (in seconds!)
int32_t DI = (buf[n] & 0x0F); // DI is low nibble
D = atr_d_table[DI]; // lookup the bitrate adjustment (yeah there are floats in it, but in iso only integers!?)
rdr_log_dbg(reader, D_ATR, "Advertised max cardfrequency is %.2f (Fmax), frequency divider is %d (Fi)", fmax / 1000000L, Fi); // High nibble TA1 contains cardspeed
rdr_log_dbg(reader, D_ATR, "Bitrate adjustment is %d (D)", D); // Low nibble TA1 contains Bitrateadjustment
rdr_log_dbg(reader, D_ATR, "Work ETU = %.2f us assuming card runs at %.2f Mhz",
(double)((1 / (double)D) * ((double)Fi / (double)fmax) * 1000000), fmax / 1000000L); // And display it...
rdr_log_dbg(reader, D_ATR, "Initial ETU = %.2f us", (double)372 / (double)fmax * 1000000); // And display it... since D=1 and frequency during ATR fetch might be different!
}
if(protocols > 1 && protocols < 3)
{
if((buf[n] & 0x80) == 0x80) { rdr_log_dbg(reader, D_ATR, "Switching between negotiable mode and specific mode is not possible"); }
else
{
rdr_log_dbg(reader, D_ATR, "Switching between negotiable mode and specific mode is possible");
// int32_t PPS = 1; Stupid compiler, will need it later on eventually
}
if((buf[n] & 0x01) == 0x01) { rdr_log_dbg(reader, D_ATR, "Transmission parameters implicitly defined in the interface characters."); }
else { rdr_log_dbg(reader, D_ATR, "Transmission parameters explicitly defined in the interface characters."); }
protocol = buf[n] & 0x0F;
if(protocol) { rdr_log_dbg(reader, D_ATR, "Protocol T = %d is to be used!", protocol); }
}
n++; // next interface character
}
if(TDi & 0x20) //TB Present
{
if(IO_Serial_Read(reader, 0, timeout, 1, buf + n)) { break; }
rdr_log_dbg(reader, D_ATR, "TB%d: %02X", protocols, buf[n]);
if((protocols > 2) && ((TDi & 0x0F) == 0x01)) // Protocol T1 specfic (There is always an obsolete T0 protocol!)
{
int32_t CWI = (buf[n] & 0x0F); // low nibble contains CWI code for the character waiting time CWT
int32_t BWI = (buf[n] >> 4); // high nibble contains BWI code for the block waiting time BWT
rdr_log_dbg(reader, D_ATR, "Protocol T1: Character waiting time is %d(CWI)", CWI);
rdr_log_dbg(reader, D_ATR, "Protocol T1: Block waiting time is %d (BWI)", BWI);
}
n++; // next interface character
}
if(TDi & 0x40) //TC Present
{
if(IO_Serial_Read(reader, 0, timeout, 1, buf + n)) { break; }
rdr_log_dbg(reader, D_ATR, "TC%d: %02X", protocols, buf[n]);
if((protocols > 1) && ((TDi & 0x0F) == 0x00))
{
int32_t WI = buf[n];
rdr_log_dbg(reader, D_ATR, "Protocol T0: work wait time is %d work etu (WWT)", (int)(960 * D * WI));
}
if((protocols > 1) && ((TDi & 0x0F) == 0x01))
{
if(buf[n] & 0x01) { rdr_log_dbg(reader, D_ATR, "Protocol T1: CRC is used to compute the error detection code"); }
else { rdr_log_dbg(reader, D_ATR, "Protocol T1: LRC is used to compute the error detection code"); }
}
if((protocols < 2) && (buf[n] < 0xFF)) { rdr_log_dbg(reader, D_ATR, "Extra guardtime of %d ETU (N)", (int) buf[n]); }
if((protocols < 2) && (buf[n] == 0xFF)) { rdr_log_dbg(reader, D_ATR, "Protocol T1: Standard 2 ETU guardtime is lowered to 1 ETU"); }
n++; // next interface character
}
if(TDi & 0x80) //TD Present? Get next TDi there will be a next protocol
{
if(IO_Serial_Read(reader, 0, timeout, 1, buf + n)) { break; }
rdr_log_dbg(reader, D_ATR, "TD%d %02X", protocols, buf[n]);
TDi = buf[n];
protocolnumber = TDi & 0x0F;
if(protocolnumber == 0x00) { tck = 0; } // T0 protocol do not use tck byte (TCK = checksum byte!)
if(protocolnumber == 0x0E) { tck = 1; } // T14 protocol tck byte should be present
if(protocolnumber == 0x01) { tck = 1; } // T1 protocol tck byte is mandatory, BTW: this code doesnt calculate if the TCK is valid jet...
rdr_log_dbg(reader, D_ATR, "Fetching global interface characters for protocol T%d:", (TDi & 0x0F)); // lower nibble contains protocol number
protocols++; // there is always 1 protocol T0 in every ATR as per iso defined, max is 16 (numbered 0..15)
n++; // next interface character
}
else { break; }
}
int32_t atrlength = 0;
atrlength += n;
atrlength += historicalbytes;
rdr_log_dbg(reader, D_ATR, "Total ATR Length including %d historical bytes should be %d", historicalbytes, atrlength);
if(T0 & 0x80) { protocols--; } // if bit 8 set there was a TD1 and also more protocols, otherwise this is a T0 card: substract 1 from total protocols
rdr_log_dbg(reader, D_ATR, "Total protocols in this ATR is %d", protocols);
while(n < atrlength + tck) // read all the rest and mandatory tck byte if other protocol than T0 is used.
{
if(IO_Serial_Read(reader, 0, timeout, 1, buf + n)) { break; }
n++;
}
if(n != atrlength + tck) { rdr_log(reader, "WARNING: Total ATR characters received is: %d instead of expected %d", n, atrlength + tck); }
if((buf[0] != 0x3B) && (buf[0] != 0x3F) && (n > 9 && !memcmp(buf + 4, "IRDETO", 6))) // irdeto S02 reports FD as first byte on dreambox SCI, not sure about SH4 or phoenix
{ buf[0] = 0x3B; }
statusreturn = ATR_InitFromArray(atr, buf, n); // n should be same as atr length but in case of atr read error it's less, so do not use atr length here!
if(buf[7] == 0x70 && buf[8] == 0x70 && (buf[9]&0x0F) >= 10)
{
const struct s_cardreader *crdr_ops = reader->crdr;
if (!crdr_ops) return ERROR;
int8_t nxtr = 0;
reader->crdr_flush = 0;
while(nxtr < 2)
{
if(IO_Serial_Read(reader, 0, 75000, 1, buf + n + nxtr)) { break; }
nxtr++;
}
}
if(statusreturn == ATR_MALFORMED) { rdr_log(reader, "WARNING: ATR is malformed, you better inspect it with a -d2 log!"); }
if(statusreturn == ERROR)
{
rdr_log(reader, "WARNING: ATR is invalid!");
return ERROR;
}
return OK; // return OK but atr might be softfailing!
}
static int32_t Sci_Reset(struct s_reader *reader, ATR *atr)
{
int32_t ret = ERROR;
SCI_PARAMETERS params;
memset(&params, 0, sizeof(SCI_PARAMETERS));
params.ETU = 372; //initial ETU (in iso this parameter F)
params.EGT = 0; //initial guardtime should be 0 (in iso this is parameter N)
params.fs = 3; //initial cardmhz 3 Mhz for non pll readers (in iso this is parameter D)
params.T = 0;
if(reader->cardmhz > 2000) // PLL based reader
{
params.ETU = 372;
params.EGT = 0;
params.fs = (int32_t)(reader->cardmhz / 100.0 + 0.5); /* calculate divider for 1 MHz */
params.T = 0;
}
if(reader->cardmhz == 8300) /* PLL based reader DM7025 */
{
params.ETU = 372;
params.EGT = 0;
params.fs = 16; /* read from table setting for 1 MHz:
params.fs = 6 for cardmhz = 5.188 MHz
params.fs = 7 for cardmhz = 4.611 MHz
params.fs = 8 for cardmhz = 3.953 MHz
params.fs = 9 for cardmhz = 3.609 MHz
params.fs = 10 for cardmhz = 3.192 MHz
params.fs = 11 for cardmhz = 2.965 MHz
params.fs = 12 for cardmhz = 2.677 MHz
params.fs = 13 for cardmhz = 2.441 MHz
params.fs = 14 for cardmhz = 2.306 MHz
params.fs = 15 for cardmhz = 2.128 MHz
params.fs = 16 for cardmhz = 1.977 MHz */
params.T = 0;
}
int32_t tries = 0;
int32_t max_tries = 0;
int32_t pll_start_fs = 0;
if (reader->cardmhz > 2000 && reader->cardmhz != 8300)
{
max_tries = (((double)(reader->cardmhz/900)) * 2 ) + 1 ; // the higher the maxpll the higher tries needed, to have 9 Mhz or first avb below.
pll_start_fs = ((double)(reader->cardmhz/300)) + 1.5 ; // first avbl reader Mhz equal or above 3.0 Mhz
}
else
{
max_tries = 5;
}
while(ret == ERROR && tries < max_tries)
{
cs_sleepms(50);
// rdr_log(reader, "Set reader parameters!");
rdr_log_dbg(reader, D_IFD, "Sent reader setting at cardinit T=%d fs=%d ETU=%d WWT=%d CWT=%d BWT=%d EGT=%d clock=%d check=%d P=%d I=%d U=%d",
(int)params.T, params.fs, (int)params.ETU, (int)params.WWT,
(int)params.CWT, (int)params.BWT, (int)params.EGT,
(int)params.clock_stop_polarity, (int)params.check,
(int)params.P, (int)params.I, (int)params.U);
ioctl(reader->handle, IOCTL_SET_PARAMETERS, &params);
cs_sleepms(150); // give the reader some time to process the params
// rdr_log(reader, "Reset internal cardreader!");
if(ioctl(reader->handle, IOCTL_SET_RESET, 1) < 0)
{
ret = ERROR;
rdr_log(reader, "Error:%s ioctl(IOCTL_SET_RESET) failed.(%d:%s)", __FUNCTION__, errno, strerror(errno) );
Sci_Deactivate(reader);
Sci_Activate(reader);
cs_sleepms(50);
}
else
{
ret = Sci_Read_ATR(reader, atr);
if(ret == ERROR)
{
Sci_Deactivate(reader);
Sci_Activate(reader);
tries++; // increase fs
if (reader->cardmhz > 2000 && reader->cardmhz != 8300)
{
params.fs = (pll_start_fs - tries); // if 1 Mhz init failed retry with min 300 Mhz up to max 9.0 Mhz
rdr_log(reader, "Read ATR fail, attempt %d/%d fs = %d", tries, max_tries, params.fs);
}
else if (reader->cardmhz == 8300)
{
params.fs = (11 - tries); // if 1 Mhz init failed retry with 3.19 Mhz up to 5.188 Mhz
rdr_log(reader, "Read ATR fail, attempt %d/5 fs = %d", tries, params.fs);
}
else
{
params.fs = (2 + tries); // if 1 Mhz init failed retry with 3.0 Mhz up to 7.0 Mhz
rdr_log(reader, "Read ATR fail, attempt %d/5 fs = %d", tries, params.fs);
}
}
else // ATR fetched successfully!
{
if(ioctl(reader->handle, IOCTL_SET_ATR_READY, 1) < 0)
{
ret = ERROR;
rdr_log(reader, "Error:%s ioctl(IOCTL_SET_ATR_READY) failed.(%d:%s)", __FUNCTION__, errno, strerror(errno) );
}
}
}
}
return ret;
}
static int32_t Sci_WriteSettings(struct s_reader *reader, unsigned char T, uint32_t fs, uint32_t ETU, uint32_t WWT, uint32_t CWT, uint32_t BWT, uint32_t EGT, unsigned char P, unsigned char I)
{
cs_sleepms(150);
struct sr_data *crdr_data = reader->crdr_data;
//int32_t n;
SCI_PARAMETERS params;
//memset(&params,0,sizeof(SCI_PARAMETERS));
ioctl(reader->handle, IOCTL_GET_PARAMETERS, &params);
params.T = T;
params.fs = fs;
//for Irdeto T14 cards, do not set ETU
if(ETU)
{ params.ETU = ETU; }
params.EGT = EGT;
params.WWT = WWT;
params.BWT = BWT;
params.CWT = CWT;
if(P)
{ params.P = P; }
if(I)
{ params.I = I; }
crdr_data->T = params.T;
crdr_data->fs = params.fs;
crdr_data->ETU = params.ETU;
crdr_data->WWT = params.WWT;
crdr_data->CWT = params.CWT;
crdr_data->BWT = params.BWT;
crdr_data->EGT = params.EGT;
crdr_data->P = params.P;
crdr_data->I = params.I;
rdr_log_dbg(reader, D_IFD, "Sent reader settings T=%d fs=%d ETU=%d WWT=%d CWT=%d BWT=%d EGT=%d clock=%d check=%d P=%d I=%d U=%d",
(int)params.T, params.fs, (int)params.ETU, (int)params.WWT,
(int)params.CWT, (int)params.BWT, (int)params.EGT,
(int)params.clock_stop_polarity, (int)params.check,
(int)params.P, (int)params.I, (int)params.U);
ioctl(reader->handle, IOCTL_SET_PARAMETERS, &params);
cs_sleepms(150); // give the reader some time to process the params
return OK;
}
static int32_t Sci_FastReset(struct s_reader *reader, ATR *atr)
{
struct sr_data *crdr_data = reader->crdr_data;
int8_t atr_ok = 1; // initiate atr in ERROR
uint32_t timeout = ATR_TIMEOUT;
unsigned char buf[SCI_MAX_ATR_SIZE];
int8_t atr_len = 0;
if(reader->seca_nagra_card == 1)
{
atr_len = reader->card_atr_length; // this is a special case the data buffer has only the atr length.
}
else
{
atr_len = reader->card_atr_length + 2; // data buffer has atr length + 2 bytes
}
Sci_Activate(reader);
cs_sleepms(50);
if(ioctl(reader->handle, IOCTL_SET_RESET, 1) < 0)
{
rdr_log(reader, "Error:%s ioctl(IOCTL_SET_RESET) failed.(%d:%s)", __FUNCTION__, errno, strerror(errno) );
Sci_Deactivate(reader);
atr_ok = ERROR;
}
else
{
IO_Serial_Read(reader, 0, timeout*10, atr_len, buf); //read atr: give some extra timeout time since on some platforms all chars are read at once
// rdr_log_dump(reader,buf, SCI_MAX_ATR_SIZE * 2, "SCI ATR :"); // just to crosscheck the buffer I left it commented.
if(ioctl(reader->handle, IOCTL_SET_ATR_READY, 1) < 0)
{
rdr_log(reader, "Error:%s ioctl(IOCTL_SET_ATR_READY) failed.(%d:%s)", __FUNCTION__, errno, strerror(errno) );
Sci_Deactivate(reader);
atr_ok = ERROR;
}
else
{
if(ATR_InitFromArray(atr, buf, atr_len) != ERROR)
{
atr_ok = OK;
}
else
{
rdr_log(reader,"Error reading ATR");
atr_ok= ERROR;
}
cs_sleepms(150);
Sci_WriteSettings(reader, crdr_data->T,crdr_data->fs,crdr_data->ETU, crdr_data->WWT,crdr_data->CWT,crdr_data->BWT,crdr_data->EGT,crdr_data->P,crdr_data->I);
cs_sleepms(150);
}
}
return atr_ok;
}
static int32_t Sci_Init(struct s_reader *reader)
{
uint8_t i = 0;
while(reader->handle_nr > 0 && i < 5)
{
i++;
rdr_log(reader," Wait On closing before restart %u", i);
cs_sleepms(1000);
}
int flags = O_RDWR | O_NOCTTY;
#if defined(__SH4__) || defined(STB04SCI)
flags |= O_NONBLOCK;
#endif
reader->handle = open(reader->device, flags);
if(reader->handle < 0)
{
rdr_log(reader, "ERROR: Opening device %s (errno=%d %s)", reader->device, errno, strerror(errno));
return ERROR;
}
if(!reader->crdr_data && !cs_malloc(&reader->crdr_data, sizeof(struct sr_data)))
{ return ERROR; }
struct sr_data *crdr_data = reader->crdr_data;
crdr_data->old_reset = 1;
reader->handle_nr = reader->handle + 1;
return OK;
}
static int32_t sci_activate(struct s_reader *reader, ATR *atr)
{
if(!reader->ins7e11_fast_reset)
{
call(Sci_Activate(reader));
call(Sci_Reset(reader, atr));
}
else
{
rdr_log_dbg(reader, D_IFD, "Fast card reset with atr");
call(Sci_FastReset(reader, atr));
}
return OK;
}
static int32_t Sci_Close(struct s_reader *reader)
{
Sci_Deactivate(reader);
IO_Serial_Close(reader);
NULLFREE(reader->crdr_data); //clearing allocated module mem
NULLFREE(reader->csystem_data); //clearing allocated card system mem
cs_sleepms(150); // some stb's needs small extra time even after close procedure seems to be ok.
reader->handle_nr = 0;
return OK;
}
static int32_t sci_write_settings(struct s_reader *reader, struct s_cardreader_settings *s)
{
if(reader->cardmhz > 2000) // only for dreambox internal pll readers clockspeed can be set precise others like vu ignore it and work always at 4.5 Mhz
{
// P fixed at 5V since this is default class A card, and TB is deprecated
if(reader->protocol_type != ATR_PROTOCOL_TYPE_T14) // fix VU+ internal reader slow responses on T0/T1
{
cs_sleepms(150);
call(Sci_WriteSettings(reader, 0, reader->divider, s->ETU, s->WWT, reader->CWT, reader->BWT, s->EGT, 5, (unsigned char)s->I));
cs_sleepms(150);
}
else // no fixup for T14 protocol otherwise error
{
cs_sleepms(150);
call(Sci_WriteSettings(reader, reader->protocol_type, reader->divider, s->ETU, s->WWT, reader->CWT, reader->BWT, s->EGT, 5, (unsigned char)s->I));
cs_sleepms(150);
}
}
else // all other brand boxes than dreamboxes or VU+!
{
// P fixed at 5V since this is default class A card, and TB is deprecated
cs_sleepms(150);
// non pll internal reader needs base frequency like 1,2,3,4,5,6 MHz not clock rate conversion factor (Fi)
call(Sci_WriteSettings(reader, reader->protocol_type, s->F/100, s->ETU, s->WWT, reader->CWT, reader->BWT, s->EGT, 5, (unsigned char)s->I));
cs_sleepms(150);
}
return OK;
}
const struct s_cardreader cardreader_internal_sci =
{
.desc = "internal",
.typ = R_INTERNAL,
.flush = 1,
.max_clock_speed = 1,
.reader_init = Sci_Init,
.get_status = Sci_GetStatus,
.activate = sci_activate,
.transmit = IO_Serial_Transmit,
.receive = IO_Serial_Receive,
.close = Sci_Close,
.write_settings = sci_write_settings,
};
#endif