oscam-2.26.01-11942-802-wit.../csctapi/ifd_stinger.c

578 lines
12 KiB
C
Raw Permalink Normal View History

/*
ifd_stinger.c
This module provides IFD handling functions for Stinger USB.
Usage:
Stinger Dedicated parameters.
cardmhz = real card clock (see smartcard docs)
mhz = stinger card clock (343, 400, 480, 600, 800, 1200)
detect = Inverted CTS
Ex.
[reader]
label = stinger_UP
protocol = stinger
detect = !cts
device = /dev/ttyUSB4
group = 2
cardmhz = 357
mhz = 600
emmcache = 1,3,2
services = services2
...
*/
#include "../globals.h"
#ifdef CARDREADER_STINGER
#include "../oscam-time.h"
#include "icc_async.h"
#include "ifd_db2com.h"
#include "ifd_phoenix.h"
#include "io_serial.h"
#define OK 0
#define ERROR 1
#define STINGER_DELAY 150
static int32_t Stinger_Set_Clock(struct s_reader *reader, unsigned int c);
static bool Stinger_IO_Serial_WaitToWrite(struct s_reader *reader, uint32_t delay_us, uint32_t timeout_us)
{
struct pollfd ufds;
struct timeb start, end;
int32_t ret_val;
int32_t out_fd;
int64_t polltimeout = timeout_us / 1000;
#if !defined(WITH_COOLAPI) && !defined(WITH_COOLAPI2) && !defined(WITH_AZBOX)
if(reader->typ == R_INTERNAL) { return OK; } // needed for internal readers, otherwise error!
#endif
if(delay_us > 0)
{ cs_sleepus(delay_us); } // wait in us
out_fd = reader->handle;
ufds.fd = out_fd;
ufds.events = POLLOUT;
ufds.revents = 0x0000;
cs_ftime(&start); // register start time
while(1)
{
ret_val = poll(&ufds, 1, polltimeout);
cs_ftime(&end); // register end time
switch(ret_val)
{
case 0:
rdr_log(reader, "ERROR: not ready to write, timeout=%"PRId64" ms", comp_timeb(&end, &start));
return ERROR;
case -1:
if(errno == EINTR || errno == EAGAIN)
{
cs_sleepus(1);
if(timeout_us > 0)
{
polltimeout = (timeout_us / 1000) - comp_timeb(&end, &start);
if(polltimeout < 0) { polltimeout = 0; }
}
continue;
}
rdr_log(reader, "ERROR: %s: timeout=%"PRId64" ms (errno=%d %s)", __func__, comp_timeb(&end, &start), errno, strerror(errno));
return ERROR;
default:
if(((ufds.revents) & POLLOUT) == POLLOUT)
{ return OK; }
else
{ return ERROR; }
}
}
}
bool Stinger_IO_Serial_Write(struct s_reader *reader, uint32_t delay, uint32_t timeout, uint32_t size, const unsigned char *data)
{
const struct s_cardreader *crdr_ops = reader->crdr;
if (!crdr_ops) return ERROR;
if(timeout == 0) // General fix for readers not communicating timeout and delay
{
if(reader->char_delay != 0) { timeout = reader->char_delay; }
else { timeout = 1000000; }
rdr_log_dbg(reader, D_DEVICE, "Warning: write timeout 0 changed to %d us", timeout);
}
uint32_t count, to_send, i_w;
unsigned char data_w[MAX_ECM_SIZE];
to_send = (delay ? 1 : size); // calculate chars to send at one
rdr_log_dbg(reader, D_DEVICE, "Write timeout %d us, write delay %d us, to send %d char(s), chunksize %d char(s)", timeout, delay, size, to_send);
for(count = 0; count < size; count += to_send)
{
if(count + to_send > size)
{
to_send = size - count;
}
uint16_t errorcount = 0, to_do = to_send;
for(i_w = 0; i_w < to_send; i_w++)
{ data_w [i_w] = data [count + i_w]; }
rdr_log_dump_dbg(reader, D_DEVICE, data_w + (to_send - to_do), to_do, "Sending:");
AGAIN:
if(!Stinger_IO_Serial_WaitToWrite(reader, delay, timeout))
{
while(to_do != 0)
{
int32_t u = write(reader->handle, data_w + (to_send - to_do), to_do);
if(u < 1)
{
if(errno == EINTR) { continue; } //try again in case of Interrupted system call
if(errno == EAGAIN) { goto AGAIN; } //EAGAIN needs a select procedure again
errorcount++;
int16_t written = count + to_send - to_do;
if(u != 0)
{
rdr_log(reader, "ERROR: %s: Written=%d of %d (errno=%d %s)",
__func__, written , size, errno, strerror(errno));
}
if(errorcount > 10) //exit if more than 10 errors
{
return ERROR;
}
}
else
{
to_do -= u;
errorcount = 0;
}
}
}
else
{
rdr_log(reader, "Timeout in Stinger_IO_Serial_WaitToWrite, delay=%d us, timeout=%d us", delay, timeout);
if(crdr_ops->read_written && reader->written > 0) // these readers need to read all transmitted chars before they can receive!
{
unsigned char buf[256];
rdr_log_dbg(reader, D_DEVICE, "Reading %d echoed transmitted chars...", reader->written);
int32_t n = reader->written;
if(IO_Serial_Read(reader, 0, 9990000, n, buf)) // use 9990000 = aprox 10 seconds (since written chars could be hughe!)
{ return ERROR; }
reader->written = 0;
rdr_log_dbg(reader, D_DEVICE, "Reading of echoed transmitted chars done!");
}
return ERROR;
}
}
return OK;
}
static int32_t Stinger_Get_Info(struct s_reader *reader, unsigned char *sc, unsigned char *parity, unsigned int *baudrate)
{
unsigned char buf[64];
memset(buf, 0, 64);
//DTR down
IO_Serial_DTR_Set(reader);
buf[0] = 0;
Stinger_IO_Serial_Write(reader, 0, 10, 1, buf);
int32_t n = 0;
while(n < 32 && !IO_Serial_Read(reader, 0, ATR_TIMEOUT, 1, buf + n))
{ n++; }
//DTR up
IO_Serial_DTR_Clr(reader);
*sc = 0xFF;
*baudrate = 0xFF;
*parity = 0xFF;
if(n == 0)
{
rdr_log(reader, "Stinger_Get_Info: n %d", n);
return ERROR;
}
if(buf[0] == 0x00)
{
/* Reader */
if((buf[1] == 0x01) || (buf[1] == 0x02))
{
*sc = buf[1] - 1;
}
else
{
rdr_log(reader, "Stinger_Get_Info: buf[1] %d", buf[1]);
return ERROR;
}
/* Baudrate */
if((buf[25] == 0x00) || (buf[25] == 0x01) || (buf[25] == 0x02))
{
*baudrate = buf[25];
}
else
{
rdr_log(reader, "Stinger_Get_Info: buf[25] %d", buf[25]);
return ERROR;
}
/* Parity */
if((buf[26] == 0x00) || (buf[26] == 0x01) || (buf[26] == 0x02))
{
*parity = buf[26];
}
else
{
rdr_log(reader, "Stinger_Get_Info: buf[26] %d", buf[26]);
return ERROR;
}
return OK;
}
else
{
rdr_log(reader, "Stinger_Get_Info: buf[0] %d", buf[0]);
return ERROR;
}
}
int32_t Stinger_Init(struct s_reader *reader)
{
// First set card in reset state, to not change any parameters while communication ongoing
IO_Serial_RTS_Set(reader);
const struct s_cardreader *crdr_ops = reader->crdr;
if (!crdr_ops) return ERROR;
if(crdr_ops->flush) { IO_Serial_Flush(reader); }
rdr_log_dbg(reader, D_IFD, "Initializing reader type=%d", reader->typ);
/* Default serial port settings */
if(reader->atr[0] == 0)
{
if(IO_Serial_SetParams(reader, DEFAULT_BAUDRATE, 8, PARITY_NONE, 2, NULL, NULL)) { return ERROR; }
if(crdr_ops->flush) { IO_Serial_Flush(reader); }
}
return OK;
}
int32_t Stinger_Reset(struct s_reader *reader, ATR *atr)
{
rdr_log_dbg(reader, D_IFD, "Resetting card");
int32_t ret;
int32_t i;
unsigned char buf[ATR_MAX_SIZE];
IO_Serial_SetParams(reader, DEFAULT_BAUDRATE, 8, PARITY_NONE, 2, NULL, NULL);
const struct s_cardreader *crdr_ops = reader->crdr;
if (!crdr_ops) return ERROR;
for(i = 0; i < 1; i++)
{
if(crdr_ops->flush) { IO_Serial_Flush(reader); }
ret = ERROR;
IO_Serial_Ioctl_Lock(reader, 1);
IO_Serial_RTS_Set(reader);
cs_sleepms(50);
IO_Serial_RTS_Clr(reader);
cs_sleepms(50);
IO_Serial_Ioctl_Lock(reader, 0);
int32_t n = 0;
while(n < 1 && !IO_Serial_Read(reader, 0, ATR_TIMEOUT, 1, buf + n))
{ n++; }
while(n < ATR_MAX_SIZE && !IO_Serial_Read(reader, 0, 900000, 1, buf + n))
{ n++; }
if(n == 0)
{ continue; }
if(ATR_InitFromArray(atr, buf, n) != ERROR)
{ ret = OK; }
// Successfully retrieve ATR
if(ret == OK)
{ break; }
}
if(ret == OK)
{
IO_Serial_SetParams(reader, 115200, 8, PARITY_NONE, 1/*2*/, NULL, NULL);
return OK;
}
else
{ return ret; }
}
static int32_t stinger_mouse_init(struct s_reader *reader)
{
unsigned int clock_mhz = 0;
const struct s_cardreader *crdr_ops = reader->crdr;
if (!crdr_ops) return ERROR;
if(detect_db2com_reader(reader))
{
reader->crdr = crdr_ops = &cardreader_db2com;
return crdr_ops->reader_init(reader);
}
clock_mhz = reader->mhz;
reader->mhz = reader->cardmhz;
reader->handle = open(reader->device, O_RDWR | O_NOCTTY | O_NONBLOCK);
if(reader->handle < 0)
{
rdr_log(reader, "ERROR: Opening device %s (errno=%d %s)",
reader->device, errno, strerror(errno));
return ERROR;
}
if(Stinger_Init(reader))
{
rdr_log(reader, "ERROR: Stinger_Init returns error");
Phoenix_Close(reader);
return ERROR;
}
// SET CLOCK
cs_sleepms(200);
Stinger_Set_Clock(reader, clock_mhz);
return OK;
}
int32_t Stinger_IO_Serial_SetBaudrate(struct s_reader *reader, uint32_t baudrate)
{
unsigned char dat[8];
unsigned char p = 0xFF;
unsigned int b = 0xFF;
unsigned char s = 0xFF;
memset(dat, 0, 8);
rdr_log_dbg(reader, D_IFD, "Setting baudrate to %u", baudrate);
if(baudrate == 9600)
{
dat[2] = 0;
}
else if(baudrate == 38400)
{
dat[2] = 1;
}
else if(baudrate == 115200)
{
dat[2] = 2;
}
else
{
rdr_log_dbg(reader, D_IFD, "Baudrate value not supported");
return ERROR;
}
Stinger_Get_Info(reader, &s, &p, &b);
if((s == 0xFF) || (p == 0xFF) || (b == 0xFF))
{
rdr_log_dbg(reader, D_IFD, "Stinger_Get_Info error");
return ERROR;
}
//Stinger cmds
dat[0] = 0x03;
dat[1] = s;
dat[3] = p;
//DTR down
IO_Serial_DTR_Set(reader);
Stinger_IO_Serial_Write(reader, 0, 10, 4, dat);
int32_t n = 0;
while(n < 2 && !IO_Serial_Read(reader, 0, 300000, 1, dat + n))
{ n++; }
//DTR up
IO_Serial_DTR_Clr(reader);
reader->current_baudrate = baudrate; //so if update fails, reader->current_baudrate is not changed either
return OK;
}
int32_t Stinger_IO_Serial_SetParity(struct s_reader *reader, unsigned char parity)
{
//Stinger cmds
unsigned char dat[4];
unsigned char p = 0xFF;
unsigned int b = 0xFF;
unsigned char s = 0xFF;
if(parity == PARITY_NONE)
{
dat[3] = 0;
}
else if(parity == PARITY_ODD)
{
dat[3] = 1;
}
else if(parity == PARITY_EVEN)
{
dat[3] = 2;
}
else
{
rdr_log_dbg(reader, D_IFD, "Parity value not supported");
return ERROR;
}
Stinger_Get_Info(reader, &s, &p, &b);
if((s == 0xFF) || (p == 0xFF) || (b == 0xFF))
{
rdr_log_dbg(reader, D_IFD, "Stinger_Get_Info error");
return ERROR;
}
//Stinger cmd
dat[0] = 0x03;
dat[1] = s;
dat[2] = b;
//DTR down
IO_Serial_DTR_Set(reader);
Stinger_IO_Serial_Write(reader, 0, 10, 4, dat);
int32_t n = 0;
while(n < 2 && !IO_Serial_Read(reader, 0, 300000, 1, dat + n))
{ n++; }
//DTR up
IO_Serial_DTR_Clr(reader);
return OK;
}
static int32_t Stinger_Set_Clock(struct s_reader *reader, unsigned int c)
{
rdr_log_dbg(reader, D_IFD, "Setting Smartcard clock at: %d", c);
unsigned char p = 0xFF;
unsigned int b = 0xFF;
unsigned char s = 0xFF;
unsigned char dat[3];
Stinger_Get_Info(reader, &s, &p, &b);
if((s == 0xFF) || (p == 0xFF) || (b == 0xFF))
{
rdr_log_dbg(reader, D_IFD, "Stinger_Get_Info error");
return ERROR;
}
//Stinger cmd
dat[0] = 0x02; // Set Clock COMMAND
dat[1] = s;
if(c == 343)
{
dat[2] = 1;
}
else if(c == 400)
{
dat[2] = 2;
}
else if(c == 480)
{
dat[2] = 3;
}
else if(c == 600)
{
dat[2] = 4;
}
else if(c == 800)
{
dat[2] = 5;
}
else if(c == 1200)
{
dat[2] = 6;
}
else
{
rdr_log_dbg(reader, D_IFD, "Clock speed not recognized. Check configuration");
return ERROR;
}
//DTR down
IO_Serial_DTR_Set(reader);
// SEND Command
Stinger_IO_Serial_Write(reader, 0, 10, 3, dat);
int32_t n = 0;
while(n < 2 && !IO_Serial_Read(reader, 0, 300000, 1, dat + n))
{ n++; }
//DTR up
IO_Serial_DTR_Clr(reader);
rdr_log_dbg(reader, D_IFD, "Smartcard clock at %d set", c);
return OK;
}
const struct s_cardreader cardreader_stinger =
{
.desc = "stinger",
.typ = R_MOUSE,
.flush = 1,
.read_written = 1,
.need_inverse = 1,
.reader_init = stinger_mouse_init,
.get_status = Phoenix_GetStatus,
.activate = Stinger_Reset,
.transmit = IO_Serial_Transmit,
.receive = IO_Serial_Receive,
.close = Phoenix_Close,
.set_parity = Stinger_IO_Serial_SetParity,
.set_baudrate = Stinger_IO_Serial_SetBaudrate,
};
#endif