- fix Building without Nagra not possible at Nagra_Merlin https://trac.streamboard...
[oscam.git] / reader-seca.c
blob33d4512229777c8ff609d5acb11281e1cdee7d1f
1 #include "globals.h"
2 #ifdef READER_SECA
3 #include "reader-common.h"
4 #include "csctapi/icc_async.h"
5 #include "cscrypt/idea.h"
7 struct seca_data
9 bool valid_provider[CS_MAXPROV];
10 IDEA_KEY_SCHEDULE ks;
11 IDEA_KEY_SCHEDULE ksSession;
15 static uint64_t get_pbm(struct s_reader *reader, uint8_t idx, bool fedc)
17 def_resp;
18 uint8_t ins34[] = { 0xc1, 0x34, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00 }; // set request options
19 uint8_t ins32[] = { 0xc1, 0x32, 0x00, 0x00, 0x0A }; // get PBM
20 uint64_t pbm = 0;
22 ins32[2] = idx;
23 if (!idx) // change request options for first (=managment) provider only
25 ins32[4] = 0x0D;
26 ins34[5] = 0x04;
29 if(!fedc)
31 write_cmd(ins34, ins34 + 5); // set request options
32 write_cmd(ins32, NULL); // pbm request
34 switch(cta_res[0])
36 case 0x04:
37 rdr_log(reader, "no PBM for provider %u", idx + 1);
38 break;
40 case 0x83:
41 pbm = b2ll(8, cta_res + 1);
42 rdr_log(reader, "PBM for provider %u: %08llx", idx + 1, (unsigned long long) pbm);
43 break;
45 case 0xb2:
46 pbm = b2ll(8, cta_res + 1);
47 rdr_log(reader, "PBM for provider %u: %08llx", idx + 1, (unsigned long long) pbm);
48 break;
50 default:
51 rdr_log(reader, "ERROR: PBM returns unknown byte %02x", cta_res[0]);
54 return pbm;
57 static int32_t set_provider_info(struct s_reader *reader, int32_t i)
59 def_resp;
60 uint8_t ins12[] = { 0xc1, 0x12, 0x00, 0x00, 0x19 }; // get provider info
61 int32_t year, month, day;
62 struct tm lt;
63 time_t t;
64 bool valid = false;
65 bool fedc = false;
66 char l_name[16 + 8 + 1] = ", name: ";
67 char tmp[9];
69 uint32_t provid;
71 ins12[2] = i; // select provider
72 rdr_log(reader, "Request provider %i", i + 1);
73 write_cmd(ins12, NULL); // show provider properties
75 if((cta_res[25] != 0x90) || (cta_res[26] != 0x00))
77 return ERROR;
80 reader->prid[i][0] = 0;
81 reader->prid[i][1] = 0; // blanken high byte provider code
83 if (cta_res[0] == 0xFE)
85 fedc = true;
86 rdr_log(reader, "FEDC provider %i", i + 1);
87 cta_res[0] = 0x00;
89 switch(i + 1)
91 case 0x01:
92 cta_res[1] = 0x00;
93 break;
95 case 0x02:
96 cta_res[1] = 0x68;
97 break;
99 case 0x03:
100 cta_res[1] = 0x65;
101 break;
103 default:
104 cta_res[1] = 0x68;
107 memcpy(&reader->prid[i][2], cta_res, 2);
109 provid = b2ll(4, reader->prid[i]);
110 year = (cta_res[22] >> 1) + 1990;
111 month = ((cta_res[22] & 0x1) << 3) | (cta_res[23] >> 5);
112 day = (cta_res[23] & 0x1f);
113 t = time(NULL);
114 localtime_r(&t, &lt);
116 if(lt.tm_year + 1900 != year)
118 valid = (lt.tm_year + 1900 < year);
120 else if(lt.tm_mon + 1 != month)
122 valid = (lt.tm_mon + 1 < month);
124 else if(lt.tm_mday != day)
126 valid = (lt.tm_mday < day);
129 memcpy(l_name + 8, cta_res + 2, 16);
130 l_name[sizeof(l_name) - 1] = 0;
131 trim(l_name + 8);
132 l_name[0] = (l_name[8]) ? ',' : 0;
134 if(l_name[8])
136 add_provider(0x0100, provid, l_name + 8, "", "");
139 struct seca_data *csystem_data = reader->csystem_data;
140 csystem_data->valid_provider[i] = valid;
141 rdr_log(reader, "provider %d: %04X, valid: %i%s, expiry date: %4d/%02d/%02d", i + 1, provid, valid, l_name, year, month, day);
142 memcpy(&reader->sa[i][0], cta_res + 18, 4);
144 if(valid) // if not expired
146 rdr_log_sensitive(reader, "SA: {%s}", cs_hexdump(0, cta_res + 18, 4, tmp, sizeof(tmp)));
149 // add entitlement to list
150 memset(&lt, 0, sizeof(struct tm));
151 lt.tm_year = year - 1900;
152 lt.tm_mon = month - 1;
153 lt.tm_mday = day;
155 // Check if entitlement entry exists
156 LL_ITER it = ll_iter_create(reader->ll_entitlements);
157 S_ENTITLEMENT *entry = NULL;
161 entry = ll_iter_next(&it);
162 if((entry) && (entry->provid == provid))
164 break;
167 while(entry);
169 if(entry)
171 // update entitlement info if found
172 entry->end = mktime(&lt);
173 entry->id = get_pbm(reader, i, fedc);
174 entry->type = (i) ? 6 : 7;
176 else // add entitlement info
178 cs_add_entitlement(reader, reader->caid, provid, get_pbm(reader, i, fedc), 0, 0, mktime(&lt), (i) ? 6 : 7, 1);
181 return OK;
184 static int32_t get_maturity(struct s_reader *reader)
186 // Get maturity on card
187 static const uint8_t ins16[] = { 0xC1, 0x16, 0x00, 0x00, 0x06 };
189 def_resp;
191 write_cmd(ins16, NULL);
192 if((cta_res[cta_lr - 2] == 0x90) && cta_res[cta_lr - 1] == 0x00)
194 reader->maturity=cta_res[cta_lr - 4] & 0xF ;
195 //rdr_log(reader, "Maturity rating on the card 0x%X!", reader->maturity);
197 if (reader->maturity<0xF)
199 rdr_log(reader, "Maturity level [%X]= older than %i years", reader->maturity, reader->maturity);
201 else
203 rdr_log(reader, "Maturity level [%X]=no age limit", reader->maturity);
207 rdr_log_dbg(reader, D_READER, "ins30_answer: %02x%02x", cta_res[0], cta_res[1]);
208 return 0;
211 static int32_t unlock_parental(struct s_reader *reader)
213 // Unlock parental control
214 // c1 30 00 01 09
215 // 00 00 00 00 00 00 00 00 ff
216 static const uint8_t ins30[] = { 0xc1, 0x30, 0x00, 0x01, 0x09 };
217 static uint8_t ins30data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF };
219 def_resp;
221 if(strcmp(reader->pincode, "none"))
223 rdr_log(reader, "Using PIN %s", reader->pincode);
224 // the pin need to be coded in bcd, so we need to convert from ascii to bcd, so '1234' -> 0x12 0x34
225 ins30data[6] = ((reader->pincode[0] - 0x30) << 4) | ((reader->pincode[1] - 0x30) & 0x0f);
226 ins30data[7] = ((reader->pincode[2] - 0x30) << 4) | ((reader->pincode[3] - 0x30) & 0x0f);
228 else
230 rdr_log(reader, "Using PIN 0000!");
233 write_cmd(ins30, ins30data);
234 rdr_log_dbg(reader, D_READER, "ins30_answer: %02x%02x", cta_res[0], cta_res[1]);
236 if(!(cta_res[cta_lr - 2] == 0x90 && cta_res[cta_lr - 1] == 0))
238 if(strcmp(reader->pincode, "none"))
240 rdr_log(reader, "Can't disable parental lock. Wrong PIN? OSCam used %s!", reader->pincode);
242 else
244 rdr_log(reader, "Can't disable parental lock. Wrong PIN? OSCam used 0000!");
247 else
249 rdr_log(reader, "Parental lock disabled");
250 get_maturity(reader);
253 return 0;
256 static int32_t seca_card_init(struct s_reader *reader, ATR *newatr)
258 get_atr;
259 def_resp;
260 char *card;
261 uint64_t serial ;
262 static const uint8_t ins0e[] = { 0xc1, 0x0e, 0x00, 0x00, 0x08 }; // get serial number (UA)
264 cs_clear_entitlement(reader);
266 if((atr[10] != 0x0e) || (atr[11] != 0x6c) || (atr[12] != 0xb6) || (atr[13] != 0xd6))
268 return ERROR;
271 if(!cs_malloc(&reader->csystem_data, sizeof(struct seca_data)))
273 return ERROR;
276 switch(atr[7] << 8 | atr[8])
278 case 0x5084:
279 card = "Generic";
280 break;
282 case 0x5384:
283 card = "Philips";
284 break;
286 case 0x5130:
287 case 0x5430:
288 case 0x5760:
289 card = "Thompson";
290 break;
292 case 0x5284:
293 case 0x5842:
294 case 0x6060:
295 card = "Siemens";
296 break;
298 case 0x7070:
299 card = "Mediaguard";
300 break;
302 default:
303 card = "Unknown";
304 break;
307 reader->caid = 0x0100;
308 memset(reader->prid, 0xff, sizeof(reader->prid));
309 write_cmd(ins0e, NULL); // read unique id
310 memcpy(reader->hexserial, cta_res + 2, 6);
311 serial = b2ll(5, cta_res + 3);
313 rdr_log_sensitive(reader, "type: SECA, caid: %04X, serial: {%llu}, card: %s v%d.%d",
314 reader->caid, (unsigned long long) serial, card, atr[9] & 0x0F, atr[9] >> 4);
316 int seca_version = atr[9] & 0X0F; // Get seca cardversion from cardatr
318 if(seca_version == 10) // check for nagra smartcard (seca3)
320 reader->secatype = 3;
321 rdr_log_dbg(reader, D_IFD, "Detected seca/nagra (seca3) card");
324 if(seca_version == 7) // check for seca smartcard (seca2)
326 reader->secatype = 2;
327 rdr_log(reader, "Detected seca2 card");
330 get_maturity(reader);
332 // Unlock parental control
333 if(cfg.ulparent != 0)
335 unlock_parental(reader);
336 get_maturity(reader);
338 else
340 rdr_log_dbg(reader, D_IFD, "parental locked");
343 struct seca_data *csystem_data = reader->csystem_data;
344 //init ideakeys
345 uint8_t IdeaKey[16];
346 memcpy(IdeaKey, reader->boxkey, 16);
347 idea_set_encrypt_key(IdeaKey, &csystem_data->ks);
348 idea_set_decrypt_key(&csystem_data->ks, &csystem_data->ksSession);
350 return OK;
353 // returns provider id or -1 if not found
354 static int32_t get_prov_index(struct s_reader *rdr, const uint8_t *provid)
356 int32_t prov;
357 for(prov = 0; prov < rdr->nprov; prov++) // search for provider index
359 if(!memcmp(provid, &rdr->prid[prov][2], 2))
361 return (prov);
364 return (-1);
367 // CDS seca2/3 solution
368 static int32_t seca_do_ecm(struct s_reader *reader, const ECM_REQUEST *er, struct s_ecm_answer *ea)
370 // provid006A=CDS NL uses seca2 and nagra/mediaguard3 crypt on same caid/provid only ecmpid is different
371 if(er->ecm[3] == 0x00 && er->ecm[4] == 0x6a)
373 // default assume ecmtype same as cardtype in reader
374 int32_t ecm_type = reader->secatype;
376 if(er->ecm[8] == 0x00) // this is a mediaguard3 ecm request
378 ecm_type = 3; // flag it!
381 if((er->ecm[8] == 0x10) && (er->ecm[9] == 0x01)) // this is a seca2 ecm request
383 ecm_type = 2; // flag it!
386 if(ecm_type != reader->secatype) // only accept ecmrequest for right card!
388 return ERROR;
392 def_resp;
393 uint8_t ins3c[] = { 0xc1, 0x3c, 0x00, 0x00, 0x00 }; // coding cw
394 uint8_t ins3a[] = { 0xc1, 0x3a, 0x00, 0x00, 0x10 }; // decoding cw
395 int32_t i;
397 if((i = get_prov_index(reader, er->ecm + 3)) == -1) // if provider not found
399 snprintf(ea->msglog, MSGLOGSIZE, "provider not found");
400 return ERROR;
403 struct seca_data *csystem_data = reader->csystem_data;
404 if((er->ecm[7] & 0x0F) != 0x0E && !csystem_data->valid_provider[i]) // if expired and not using OP Key 0E
406 snprintf(ea->msglog, MSGLOGSIZE, "provider expired");
407 return ERROR;
410 ins3c[2] = i;
411 ins3c[3] = er->ecm[7]; // key nr
412 ins3c[4] = (((er->ecm[1] & 0x0f) << 8) | er->ecm[2]) - 0x05;
413 int32_t try = 1;
414 int32_t ret;
418 if(try > 1)
420 snprintf(ea->msglog, MSGLOGSIZE, "ins3c try nr %i", try);
423 write_cmd(ins3c, er->ecm + 8); // ecm request
424 uint8_t ins30[] = { 0xC1, 0x30, 0x00, 0x02, 0x09 };
425 uint8_t ins30data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF };
427 /* We need to use a token */
428 if(cta_res[0] == 0x90 && cta_res[1] == 0x1a)
430 write_cmd(ins30, ins30data);
431 write_cmd(ins3c, er->ecm + 8); // ecm request
434 ret = (((cta_res[0] != 0x90) && (cta_res[0] != 0x93) && (cta_res[0] != 0x96)) || ((cta_res[1] != 0x00) && (cta_res[1] != 0x02)));
436 // Handle all not initial 90 00 ecm of with a get decoding cw
437 // does avoid the need off card reset after a lot off them
438 // the try ++ has been removed as it triggers the anti share mode
439 // off seca cards due to not recorded extra ecm's by rate limiter
441 if((cta_res[0] == 0x93) && (cta_res[1] == 0x02))
443 write_cmd(ins3a, NULL); // get cw
444 if(er->ecm[2] > 0x61 && er->ecm[7] == 0x5C && er->ecm[100] == 0x0B)
446 rdr_log(reader, "reinit card in CAK7 mode");
448 else
450 snprintf(ea->msglog, MSGLOGSIZE, "unsubscribed 93 02");
452 return ERROR;
453 } // exit if unsubscribed
455 if((cta_res[0] == 0x96) && (cta_res[1] == 0x00))
457 write_cmd(ins3a, NULL); // get cw
458 if(er->ecm[2] > 0x61 && er->ecm[7] == 0x5C && er->ecm[100] == 0x0B) {
459 rdr_log(reader, "reinit card in CAK7 mode");
460 } else {
461 snprintf(ea->msglog, MSGLOGSIZE, "fake 96 00 ecm");
463 return E_CORRUPT;
464 } // exit if fake 96 00 ecm
466 if(ret)
468 snprintf(ea->msglog, MSGLOGSIZE, "%.16s ins3c card res: %02x %02x", reader->label, cta_res[0] , cta_res[1]);
469 write_cmd(ins3a, NULL); // get cw
470 return ERROR;
471 } // exit on other's then 96 00 or 93 02
474 while((try < 2) && (ret));
476 if(ret)
478 return ERROR;
481 write_cmd(ins3a, NULL); // get cw's
482 if((cta_res[16] != 0x90) || (cta_res[17] != 0x00))
484 snprintf(ea->msglog, MSGLOGSIZE, "ins3a card response: %02x %02x", cta_res[16] , cta_res[17]);
485 return ERROR;
486 } // exit if response not 90 00
488 // TODO: if response is 9027 ppv mode is possible!
490 if(er->ecm[5] == 0x01 && ((reader->card_atr[9] & 0X0F) == 10)) // seca3: nano 01 in effect?
492 if(reader->boxkey_length == 16)
494 uint8_t v[8];
495 memset(v, 0, sizeof(v));
496 idea_cbc_encrypt(cta_res, ea->cw, 8, &csystem_data->ksSession, v, IDEA_DECRYPT);
497 memset(v, 0, sizeof(v));
498 idea_cbc_encrypt(cta_res + 8, ea->cw + 8, 8, &csystem_data->ksSession, v, IDEA_DECRYPT);
499 uint8_t c;
501 for(i = 0; i < 16; i += 4)
503 c = ((ea->cw[i] + ea->cw[i + 1] + ea->cw[i + 2]) & 0xff);
505 if(ea->cw[i + 3] != c)
507 break;
511 if(i == 16)
513 return OK;
516 memset(ea->cw, 0, 16);
517 snprintf(ea->msglog, MSGLOGSIZE, "need sessionkey");
518 return ERROR;
520 memcpy(ea->cw, cta_res, 16);
521 return OK;
524 // returns 1 if shared emm matches SA, unique emm matches serial, or global or unknown
525 static int32_t seca_get_emm_type(EMM_PACKET *ep, struct s_reader *rdr)
527 rdr_log_dbg(rdr, D_EMM, "Entered seca_get_emm_type ep->emm[0]=%i", ep->emm[0]);
528 int32_t i;
529 char tmp_dbg[25];
531 switch(ep->emm[0])
533 case 0x82:
534 ep->type = UNIQUE;
535 memset(ep->hexserial, 0, 8);
536 memcpy(ep->hexserial, ep->emm + 3, 6);
538 rdr_log_dbg_sensitive(rdr, D_EMM, "UNIQUE, ep->hexserial = {%s}",
539 cs_hexdump(1, ep->hexserial, 6, tmp_dbg, sizeof(tmp_dbg)));
541 rdr_log_dbg_sensitive(rdr, D_EMM, "UNIQUE, rdr->hexserial = {%s}",
542 cs_hexdump(1, rdr->hexserial, 6, tmp_dbg, sizeof(tmp_dbg)));
544 return (!memcmp(rdr->hexserial, ep->hexserial, 6));
545 break;
547 case 0x84:
548 ep->type = SHARED;
549 memset(ep->hexserial, 0, 8);
550 memcpy(ep->hexserial, ep->emm + 5, 3); // don't include custom byte; this way the network also knows SA
551 i = get_prov_index(rdr, ep->emm + 3);
553 rdr_log_dbg_sensitive(rdr, D_EMM, "SHARED, ep->hexserial = {%s}",
554 cs_hexdump(1, ep->hexserial, 3, tmp_dbg, sizeof(tmp_dbg)));
556 if(i == -1) // provider not found on this card
557 { return 0; } //do not pass this EMM
559 rdr_log_dbg_sensitive(rdr, D_EMM, "SHARED, rdr->sa[%i] = {%s}", i,
560 cs_hexdump(1, rdr->sa[i], 3, tmp_dbg, sizeof(tmp_dbg)));
562 return (!memcmp(rdr->sa[i], ep->hexserial, 3));
563 break;
565 // Unknown EMM types, but allready subbmited to dev's
566 // FIXME: Drop EMM's until there are implemented
567 case 0x83:
568 ep->type = GLOBAL;
569 rdr_log_dbg(rdr, D_EMM, "GLOBAL, PROVID: %04X", (ep->emm[3] << 8) | ep->emm[4]);
570 return 1;
571 /* EMM-G manadge ppv by provid
572 83 00 74 33 41 04 70 00 BF 20 A1 15 48 1B 88 FF
573 CF F5 50 CB 6F E1 26 A2 70 02 8F D0 07 6A 13 F9
574 50 F9 61 88 FB E4 B8 03 EF 68 C9 54 EB C0 51 2E
575 9D F9 E1 4A D9 A6 3F 5D 7A 1E B0 6E 3D 9B 93 E7
576 5A E8 D4 AE 29 B9 37 07 5A 43 C8 F2 DE BD F8 BA
577 69 DC A4 87 C2 FA 25 87 87 42 47 67 AE B7 1A 54
578 CA F6 B7 EC 15 0A 67 1C 59 F8 B9 B8 6F 7D 58 94
579 24 63 17 15 58 1E 59
582 case 0x88:
583 case 0x89:
584 // EMM-G ?
585 ep->type = UNKNOWN;
586 return 0;
588 default:
589 ep->type = UNKNOWN;
590 return 1;
594 static int32_t seca_get_emm_filter(struct s_reader *rdr, struct s_csystem_emm_filter **emm_filters, unsigned int *filter_count)
596 if(*emm_filters == NULL)
598 const unsigned int max_filter_count = 1 + (2 * rdr->nprov);
599 if(!cs_malloc(emm_filters, max_filter_count * sizeof(struct s_csystem_emm_filter)))
601 return ERROR;
604 struct s_csystem_emm_filter *filters = *emm_filters;
605 *filter_count = 0;
607 int32_t idx = 0;
609 filters[idx].type = EMM_UNIQUE;
610 filters[idx].enabled = 1;
611 filters[idx].filter[0] = 0x82;
612 filters[idx].mask[0] = 0xFF;
613 memcpy(&filters[idx].filter[1], rdr->hexserial, 6);
614 memset(&filters[idx].mask[1], 0xFF, 6);
615 idx++;
617 int32_t prov;
618 for(prov = 0; prov < rdr->nprov; prov++)
620 // if sa == null skip update by shared & global (provid inactive)
621 if(!memcmp(rdr->sa[prov], "\x00\x00\x00", 3))
623 continue;
626 filters[idx].type = EMM_GLOBAL; // global by provider
627 filters[idx].enabled = 1;
628 filters[idx].filter[0] = 0x83;
629 filters[idx].mask[0] = 0xFF;
630 memcpy(&filters[idx].filter[1], &rdr->prid[prov][2], 2);
631 memset(&filters[idx].mask[1], 0xFF, 2);
632 idx++;
634 filters[idx].type = EMM_SHARED;
635 filters[idx].enabled = 1;
636 filters[idx].filter[0] = 0x84;
637 filters[idx].mask[0] = 0xFF;
638 memcpy(&filters[idx].filter[1], &rdr->prid[prov][2], 2);
639 memset(&filters[idx].mask[1], 0xFF, 2);
640 memcpy(&filters[idx].filter[3], &rdr->sa[prov], 3);
641 memset(&filters[idx].mask[3], 0xFF, 3);
642 idx++;
645 *filter_count = idx;
648 return OK;
651 static int32_t seca_do_emm(struct s_reader *reader, EMM_PACKET *ep)
653 def_resp;
654 uint8_t ins40[] = { 0xc1, 0x40, 0x00, 0x00, 0x00 };
655 int32_t i, ins40data_offset;
656 int32_t emm_length = ((ep->emm[1] & 0x0f) << 8) + ep->emm[2];
657 uint8_t *prov_id_ptr;
659 switch(ep->type)
661 case SHARED:
662 ins40[3] = ep->emm[9];
663 ins40[4] = emm_length - 0x07;
664 ins40data_offset = 10;
665 prov_id_ptr = ep->emm + 3;
666 break;
668 case UNIQUE:
669 ins40[3] = ep->emm[12];
670 ins40[4] = emm_length - 0x0A;
671 ins40data_offset = 13;
672 prov_id_ptr = ep->emm + 9;
673 break;
675 case GLOBAL:
676 ins40[3] = ep->emm[6];
677 ins40[4] = emm_length - 0x04;
678 ins40data_offset = 7;
679 prov_id_ptr = ep->emm + 3;
680 break;
682 default:
683 rdr_log(reader, "EMM: Congratulations, you have discovered a new EMM on SECA.");
684 rdr_log(reader, "This has not been decoded yet, so send this output to authors:");
685 rdr_log_dump(reader, ep->emm, emm_length + 3, "EMM:");
686 return ERROR;
689 i = get_prov_index(reader, prov_id_ptr);
690 if(i == -1)
692 rdr_log(reader, "EMM: skipped since provider id doesnt match");
693 return SKIPPED;
696 ins40[2] = (ep->emm[ins40data_offset - 2] & 0xF0) | (i & 0x0F);
697 write_cmd(ins40, ep->emm + ins40data_offset); // emm request
699 if(cta_res[0] == 0x97)
701 if(!(cta_res[1] & 4)) // date updated
703 set_provider_info(reader, i);
705 else
707 rdr_log(reader, "EMM: Update not necessary.");
709 return OK; // Update not necessary
712 if((cta_res[0] == 0x90) && ((cta_res[1] == 0x00) || (cta_res[1] == 0x19)))
714 if(ep->type == GLOBAL) // do not print new provider info after global emm
716 return OK;
719 if(set_provider_info(reader, i) == OK) // after successful EMM, print32_t new provider info
721 return OK;
724 return ERROR;
727 static int32_t seca_card_info(struct s_reader *reader)
729 def_resp;
730 static const uint8_t ins16[] = { 0xc1, 0x16, 0x00, 0x00, 0x06 }; // get nr. of providers
731 int32_t prov = 0;
732 uint16_t pmap = 0; // provider-maptable
734 int16_t tries = 0;
735 int16_t i = 0;
737 while(reader->nprov == 0 && tries < 254)
739 write_cmd(ins16, NULL); // read nr of providers
740 pmap = cta_res[2] << 8 | cta_res[3];
742 for(reader->nprov = 0, i = pmap; i; i >>= 1)
744 reader->nprov += i & 1;
747 if(reader->nprov == 0)
749 tries++;
750 continue;
754 for(prov = 0; prov < reader->nprov; prov++)
756 set_provider_info(reader, prov);
758 return OK;
761 const struct s_cardsystem reader_seca =
763 .desc = "seca",
764 .caids = (uint16_t[]){ 0x01, 0 },
765 .do_emm = seca_do_emm,
766 .do_ecm = seca_do_ecm,
767 .card_info = seca_card_info,
768 .card_init = seca_card_init,
769 .get_emm_type = seca_get_emm_type,
770 .get_emm_filter = seca_get_emm_filter,
773 #endif