-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSCCIAdapter.cpp
More file actions
241 lines (218 loc) · 5.49 KB
/
SCCIAdapter.cpp
File metadata and controls
241 lines (218 loc) · 5.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <dlfcn.h>
#include <linux/dvb/ca.h>
#include <vdr/channels.h>
#include <vdr/ci.h>
#include <vdr/dvbdevice.h>
#include <vdr/dvbci.h>
#include <vdr/thread.h>
#include "SCCIAdapter.h"
#include "Frame.h"
// from vdr's ci.c
#define T_CREATE_TC 0x82
#define T_RCV 0x81
#define T_DATA_LAST 0xA0
SCCIAdapter::SCCIAdapter(SCDVBDevice *sCDVBDevice, int cardIndex)
{
// isyslog("DVBAPI: SCCIAdapter::SCCIAdapter");
this->sCDVBDevice=sCDVBDevice;
this->cardIndex=cardIndex;
memset(version,1,sizeof(version));
memset(slots,0,sizeof(slots));
caidsLength=0;
for(cChannel *channel=Channels.First(); channel; channel=Channels.Next(channel))
{
if(!channel->GroupSep() && channel->Ca()>=CA_ENCRYPTED_MIN)
{
for(const int *ids=channel->Caids(); *ids; ids++)
addCaid(0,caidsLength,(unsigned short)*ids);
}
}
rb=new cRingBufferLinear(KILOBYTE(8),6+LEN_OFF,false,"SC-CI adapter read");
if(rb)
{
rb->SetTimeouts(0,CAM_READ_TIMEOUT);
frame.SetRb(rb);
}
isyslog("DVBAPI: SCCIAdapter::SCCIAdapter build caid table with %i caids for %i channels",caidsLength,Channels.Count());
SetDescription("SC-CI adapter on device %d",cardIndex);
for(int i=0; i<MAX_CI_SLOTS && i*MAX_CI_SLOT_CAIDS<caidsLength; i++)
slots[i]=new SCCAMSlot(this,cardIndex,i);
Start();
}
SCDVBDevice *SCCIAdapter::GetDevice()
{
return sCDVBDevice;
}
int SCCIAdapter::addCaid(int offset,int limit,unsigned short caid)
{
if((caids[offset]==caid))
return offset;
if((limit==0) || (caidsLength==0))
{
if((caid>caids[offset]) && (offset<caidsLength))
offset++;
if(offset<caidsLength)
memmove(&caids[offset+1],&caids[offset],(caidsLength-offset)*sizeof(int));
caidsLength++;
caids[offset]=caid;
return offset;
}
if(caid>caids[offset])
{
offset=offset+limit;
if(offset>caidsLength)
offset=caidsLength;
}
else if(caid<caids[offset])
{
offset=offset-limit;
if(offset<0)
offset=0;
}
if(limit==1)
limit=0;
else
limit=ceil(((float)limit)/2.0f);
if(offset+limit>caidsLength)
offset=caidsLength-limit;
return addCaid(offset,limit,caid);
}
int SCCIAdapter::GetCaids(int slot, unsigned short *Caids, int max)
{
cMutexLock lock(&ciMutex);
if(Caids)
{
int i;
for(i=0; i<MAX_CI_SLOT_CAIDS && i<max && slot*MAX_CI_SLOT_CAIDS+i<caidsLength && caids[slot*MAX_CI_SLOT_CAIDS+i]; i++)
Caids[i]=caids[slot*MAX_CI_SLOT_CAIDS+i];
Caids[i]=0;
}
return version[slot];
}
int SCCIAdapter::Read(unsigned char *Buffer, int MaxLength)
{
// isyslog("DVBAPI: SCCIAdapter::Read");
cMutexLock lock(&ciMutex);
if(rb && Buffer && MaxLength>0)
{
int s;
unsigned char *data=frame.Get(s);
if(data)
{
if(s<=MaxLength)
memcpy(Buffer,data,s);
else
isyslog("DVBAPI: internal: sc-ci %d rb frame size exceeded %d",cardIndex,s);
frame.Del();
if(Buffer[2]!=0x80)
readTimer.Set();
return s;
}
}
else
cCondWait::SleepMs(CAM_READ_TIMEOUT);
if(readTimer.Elapsed()>2000)
readTimer.Set();
return 0;
}
#define TPDU(data,slot) do { unsigned char *_d=(data); _d[0]=(slot); _d[1]=tcid; } while(0)
#define TAG(data,tag,len) do { unsigned char *_d=(data); _d[0]=(tag); _d[1]=(len); } while(0)
#define SB_TAG(data,sb) do { unsigned char *_d=(data); _d[0]=0x80; _d[1]=0x02; _d[2]=tcid; _d[3]=(sb); } while(0)
void SCCIAdapter::Write(const unsigned char *buff, int len)
{
cMutexLock lock(&ciMutex);
if(buff && len>=5)
{
struct TPDU *tpdu=(struct TPDU *)buff;
int slot=tpdu->slot;
if(slots[slot])
{
Frame *slotframe=slots[slot]->getFrame();
switch(tpdu->tag)
{
case T_RCV:
{
int s;
unsigned char *d=slotframe->Get(s);
if(d)
{
unsigned char *b;
if((b=frame.GetBuff(s+6)))
{
TPDU(b,slot);
memcpy(b+2,d,s);
slotframe->Del(); // delete from rb before Avail()
SB_TAG(b+2+s,slotframe->Avail()>0 ? 0x80:0x00);
frame.Put();
}
else
slotframe->Del();
}
break;
}
case T_CREATE_TC:
{
tcid=tpdu->data[0];
unsigned char *b;
static const unsigned char reqCAS[] = { 0xA0,0x07,0x01,0x91,0x04,0x00,0x03,0x00,0x41 };
if((b=slotframe->GetBuff(sizeof(reqCAS))))
{
memcpy(b,reqCAS,sizeof(reqCAS));
b[2]=tcid;
slotframe->Put();
}
if((b=frame.GetBuff(9)))
{
TPDU(b,slot);
TAG(&b[2],0x83,0x01);
b[4]=tcid;
SB_TAG(&b[5],slotframe->Avail()>0 ? 0x80:0x00);
frame.Put();
}
break;
}
case T_DATA_LAST:
{
slots[slot]->Process(buff,len);
unsigned char *b;
if((b=frame.GetBuff(6)))
{
TPDU(b,slot);
SB_TAG(&b[2],slotframe->Avail()>0 ? 0x80:0x00);
frame.Put();
}
break;
}
}
}
}
else
esyslog("DVBAPI short write (cardIndex=%d buff=%d len=%d)",cardIndex,buff!=0,len);
}
SCCIAdapter::~SCCIAdapter()
{
}
bool SCCIAdapter::Ready(void)
{
return true;
}
bool SCCIAdapter::Reset(int Slot)
{
// isyslog("DVBAPI: SCCIAdapter::Reset Slot=%i",Slot);
return true;//slots[Slot]->Reset();
}
eModuleStatus SCCIAdapter::ModuleStatus(int Slot)
{
//isyslog("DVBAPI: SCCIAdapter::ModuleStatus");
return (slots[Slot]) ? slots[Slot]->Status():msNone;
}
bool SCCIAdapter::Assign(cDevice *Device, bool Query)
{
//isyslog("DVBAPI: SCCIAdapter::Assign");
return true;
}