[PATCH] dvb: DST: reorganize Twinhan DST driver to support CI
[safe/jmp/linux-2.6] / drivers / media / dvb / bt8xx / dst_ca.c
1 /*
2         CA-driver for TwinHan DST Frontend/Card
3
4         Copyright (C) 2004, 2005 Manu Abraham (manu@kromtek.com)
5
6         This program is free software; you can redistribute it and/or modify
7         it under the terms of the GNU General Public License as published by
8         the Free Software Foundation; either version 2 of the License, or
9         (at your option) any later version.
10
11         This program is distributed in the hope that it will be useful,
12         but WITHOUT ANY WARRANTY; without even the implied warranty of
13         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14         GNU General Public License for more details.
15
16         You should have received a copy of the GNU General Public License
17         along with this program; if not, write to the Free Software
18         Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21
22
23 #include <linux/kernel.h>
24 #include <linux/module.h>
25 #include <linux/init.h>
26 #include <linux/string.h>
27
28 #include <linux/dvb/ca.h>
29 #include "dvbdev.h"
30 #include "dvb_frontend.h"
31
32 #include "dst_ca.h"
33 #include "dst_common.h"
34
35 static unsigned int verbose = 1;
36 module_param(verbose, int, 0644);
37 MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)");
38
39 static unsigned int debug = 1;
40 module_param(debug, int, 0644);
41 MODULE_PARM_DESC(dst_ca_debug, "debug messages, default is 0 (yes)");
42
43 static unsigned int session;
44 module_param(session, int, 0644);
45 MODULE_PARM_DESC(session, "Support for hardware that has multiple sessions, default 0");
46
47 static unsigned int new_ca;
48 module_param(new_ca, int, 0644);
49 MODULE_PARM_DESC(new_ca, "Support for the new CA interface firmware, default 0");
50
51 #define dprintk if (debug) printk
52
53
54 static int ca_set_slot_descr(void)
55 {
56         /*      We could make this more graceful ?      */
57         return -EOPNOTSUPP;
58 }
59
60 static int ca_set_pid(void)
61 {
62         /*      We could make this more graceful ?      */
63         return -EOPNOTSUPP;
64 }
65
66
67 static int put_checksum(u8 *check_string, int length)
68 {
69         u8 i = 0, checksum = 0;
70
71         if (verbose > 3) {
72                 dprintk("%s: ========================= Checksum calculation ===========================\n", __FUNCTION__);
73                 dprintk("%s: String Length=[0x%02x]\n", __FUNCTION__, length);
74
75                 dprintk("%s: String=[", __FUNCTION__);
76         }
77         while (i < length) {
78                 if (verbose > 3)
79                         dprintk(" %02x", check_string[i]);
80                 checksum += check_string[i];
81                 i++;
82         }
83         if (verbose > 3) {
84                 dprintk(" ]\n");
85                 dprintk("%s: Sum=[%02x]\n", __FUNCTION__, checksum);
86         }
87         check_string[length] = ~checksum + 1;
88         if (verbose > 3) {
89                 dprintk("%s: Checksum=[%02x]\n", __FUNCTION__, check_string[length]);
90                 dprintk("%s: ==========================================================================\n", __FUNCTION__);
91         }
92
93         return 0;
94 }
95
96 static int dst_ci_command(struct dst_state* state, u8 * data, u8 *ca_string, u8 len, int read)
97 {
98         u8 reply;
99
100         dst_comm_init(state);
101         msleep(65);
102
103         if (write_dst(state, data, len)) {
104                 dprintk("%s: Write not successful, trying to recover\n", __FUNCTION__);
105                 dst_error_recovery(state);
106                 return -1;
107         }
108
109         if ((dst_pio_disable(state)) < 0) {
110                 dprintk("%s: DST PIO disable failed.\n", __FUNCTION__);
111                 return -1;
112         }
113
114         if (read_dst(state, &reply, GET_ACK) < 0) {
115                 dprintk("%s: Read not successful, trying to recover\n", __FUNCTION__);
116                 dst_error_recovery(state);
117                 return -1;
118         }
119
120         if (read) {
121                 if (! dst_wait_dst_ready(state, LONG_DELAY)) {
122                         dprintk("%s: 8820 not ready\n", __FUNCTION__);
123                         return -1;
124                 }
125
126                 if (read_dst(state, ca_string, 128) < 0) {      /*      Try to make this dynamic        */
127                         dprintk("%s: Read not successful, trying to recover\n", __FUNCTION__);
128                         dst_error_recovery(state);
129                         return -1;
130                 }
131         }
132
133         return 0;
134 }
135
136
137 static int dst_put_ci(struct dst_state *state, u8 *data, int len, u8 *ca_string, int read)
138 {
139         u8 dst_ca_comm_err = 0;
140
141         while (dst_ca_comm_err < RETRIES) {
142                 dst_comm_init(state);
143                 if (verbose > 2)
144                         dprintk("%s: Put Command\n", __FUNCTION__);
145                 if (dst_ci_command(state, data, ca_string, len, read)) {        // If error
146                         dst_error_recovery(state);
147                         dst_ca_comm_err++; // work required here.
148                 }
149                 break;
150         }
151
152         return 0;
153 }
154
155
156
157 static int ca_get_app_info(struct dst_state *state)
158 {
159         static u8 command[8] = {0x07, 0x40, 0x01, 0x00, 0x01, 0x00, 0x00, 0xff};
160
161         put_checksum(&command[0], command[0]);
162         if ((dst_put_ci(state, command, sizeof(command), state->messages, GET_REPLY)) < 0) {
163                 dprintk("%s: -->dst_put_ci FAILED !\n", __FUNCTION__);
164                 return -1;
165         }
166         if (verbose > 1) {
167                 dprintk("%s: -->dst_put_ci SUCCESS !\n", __FUNCTION__);
168
169                 dprintk("%s: ================================ CI Module Application Info ======================================\n", __FUNCTION__);
170                 dprintk("%s: Application Type=[%d], Application Vendor=[%d], Vendor Code=[%d]\n%s: Application info=[%s]\n",
171                         __FUNCTION__, state->messages[7], (state->messages[8] << 8) | state->messages[9],
172                         (state->messages[10] << 8) | state->messages[11], __FUNCTION__, (char *)(&state->messages[11]));
173                 dprintk("%s: ==================================================================================================\n", __FUNCTION__);
174         }
175
176         return 0;
177 }
178
179 static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps, void *arg)
180 {
181         int i;
182         u8 slot_cap[256];
183         static u8 slot_command[8] = {0x07, 0x40, 0x02, 0x00, 0x02, 0x00, 0x00, 0xff};
184
185         put_checksum(&slot_command[0], slot_command[0]);
186         if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_cap, GET_REPLY)) < 0) {
187                 dprintk("%s: -->dst_put_ci FAILED !\n", __FUNCTION__);
188                 return -1;
189         }
190         if (verbose > 1)
191                 dprintk("%s: -->dst_put_ci SUCCESS !\n", __FUNCTION__);
192
193         /*      Will implement the rest soon            */
194
195         if (verbose > 1) {
196                 dprintk("%s: Slot cap = [%d]\n", __FUNCTION__, slot_cap[7]);
197                 dprintk("===================================\n");
198                 for (i = 0; i < 8; i++)
199                         dprintk(" %d", slot_cap[i]);
200                 dprintk("\n");
201         }
202
203         p_ca_caps->slot_num = 1;
204         p_ca_caps->slot_type = 1;
205         p_ca_caps->descr_num = slot_cap[7];
206         p_ca_caps->descr_type = 1;
207
208
209         if (copy_to_user((struct ca_caps *)arg, p_ca_caps, sizeof (struct ca_caps))) {
210                 return -EFAULT;
211         }
212
213         return 0;
214 }
215
216
217 static int ca_get_slot_descr(struct dst_state *state, struct ca_msg *p_ca_message, void *arg)
218 {
219         return -EOPNOTSUPP;
220 }
221
222
223 static int ca_get_slot_info(struct dst_state *state, struct ca_slot_info *p_ca_slot_info, void *arg)
224 {
225         int i;
226         static u8 slot_command[8] = {0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff};
227
228         u8 *slot_info = state->rxbuffer;
229
230         put_checksum(&slot_command[0], 7);
231         if ((dst_put_ci(state, slot_command, sizeof (slot_command), slot_info, GET_REPLY)) < 0) {
232                 dprintk("%s: -->dst_put_ci FAILED !\n", __FUNCTION__);
233                 return -1;
234         }
235         if (verbose > 1)
236                 dprintk("%s: -->dst_put_ci SUCCESS !\n", __FUNCTION__);
237
238         /*      Will implement the rest soon            */
239
240         if (verbose > 1) {
241                 dprintk("%s: Slot info = [%d]\n", __FUNCTION__, slot_info[3]);
242                 dprintk("===================================\n");
243                 for (i = 0; i < 8; i++)
244                         dprintk(" %d", slot_info[i]);
245                 dprintk("\n");
246         }
247
248         if (slot_info[4] & 0x80) {
249                 p_ca_slot_info->flags = CA_CI_MODULE_PRESENT;
250                 p_ca_slot_info->num = 1;
251                 p_ca_slot_info->type = CA_CI;
252         }
253         else if (slot_info[4] & 0x40) {
254                 p_ca_slot_info->flags = CA_CI_MODULE_READY;
255                 p_ca_slot_info->num = 1;
256                 p_ca_slot_info->type = CA_CI;
257         }
258         else {
259                 p_ca_slot_info->flags = 0;
260         }
261
262         if (copy_to_user((struct ca_slot_info *)arg, p_ca_slot_info, sizeof (struct ca_slot_info))) {
263                 return -EFAULT;
264         }
265
266         return 0;
267 }
268
269
270
271
272 static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, void *arg)
273 {
274         u8 i = 0;
275         u32 command = 0;
276
277         if (copy_from_user(p_ca_message, (void *)arg, sizeof (struct ca_msg)))
278                 return -EFAULT;
279
280
281         if (p_ca_message->msg) {
282                 if (verbose > 3)
283                         dprintk("Message = [%02x %02x %02x]\n", p_ca_message->msg[0], p_ca_message->msg[1], p_ca_message->msg[2]);
284
285                 for (i = 0; i < 3; i++) {
286                         command = command | p_ca_message->msg[i];
287                         if (i < 2)
288                                 command = command << 8;
289                 }
290                 if (verbose > 3)
291                         dprintk("%s:Command=[0x%x]\n", __FUNCTION__, command);
292
293                 switch (command) {
294                         case CA_APP_INFO:
295                                 memcpy(p_ca_message->msg, state->messages, 128);
296                                 if (copy_to_user((void *)arg, p_ca_message, sizeof (struct ca_msg)) )
297                                         return -EFAULT;
298                         break;
299                 }
300         }
301
302         return 0;
303 }
304
305 static int handle_en50221_tag(struct ca_msg *p_ca_message, struct ca_msg *hw_buffer)
306 {
307         if (session) {
308                 hw_buffer->msg[2] = p_ca_message->msg[1];               /*              MSB                     */
309                 hw_buffer->msg[3] = p_ca_message->msg[2];               /*              LSB                     */
310         }
311         else {
312                 hw_buffer->msg[2] = 0x03;
313                 hw_buffer->msg[3] = 0x00;
314         }
315         return 0;
316 }
317
318 static int debug_8820_buffer(struct ca_msg *hw_buffer)
319 {
320         unsigned int i;
321
322         dprintk("%s:Debug=[", __FUNCTION__);
323         for (i = 0; i < (hw_buffer->msg[0] + 1); i++)
324                 dprintk(" %02x", hw_buffer->msg[i]);
325         dprintk("]\n");
326
327         return 0;
328 }
329
330 static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 reply)
331 {
332         if ((dst_put_ci(state, hw_buffer->msg, (hw_buffer->length + 1), hw_buffer->msg, reply)) < 0) {
333                 dprintk("%s: DST-CI Command failed.\n", __FUNCTION__);
334                 dprintk("%s: Resetting DST.\n", __FUNCTION__);
335                 rdc_reset_state(state);
336                 return -1;
337         }
338         if (verbose > 2)
339                 dprintk("%s: DST-CI Command succes.\n", __FUNCTION__);
340
341         return 0;
342 }
343
344
345 static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query)
346 {
347         u32 hw_offset, buf_offset, i, k;
348         u32 program_info_length = 0, es_info_length = 0, length = 0, words = 0;
349         u8 found_prog_ca_desc = 0, found_stream_ca_desc = 0, error_condition = 0, hw_buffer_length = 0;
350
351         if (verbose > 3)
352                 dprintk("%s, p_ca_message length %d (0x%x)\n", __FUNCTION__,p_ca_message->length,p_ca_message->length );
353
354         handle_en50221_tag(p_ca_message, hw_buffer);                    /*      EN50221 tag             */
355
356         /*      Handle the length field (variable)      */
357         if (!(p_ca_message->msg[3] & 0x80)) {                           /*      Length = 1              */
358                 length = p_ca_message->msg[3] & 0x7f;
359                 words = 0;                                              /*      domi's suggestion       */
360         }
361         else {                                                          /*      Length = words          */
362                 words = p_ca_message->msg[3] & 0x7f;
363                 for (i = 0; i < words; i++) {
364                         length = length << 8;
365                         length = length | p_ca_message->msg[4 + i];
366                 }
367         }
368         if (verbose > 4) {
369                 dprintk("%s:Length=[%d (0x%x)], Words=[%d]\n", __FUNCTION__, length,length, words);
370
371                 /*      Debug Input string              */
372                 for (i = 0; i < length; i++)
373                         dprintk(" %02x", p_ca_message->msg[i]);
374                 dprintk("]\n");
375         }
376
377         hw_offset = 7;
378         buf_offset = words + 4;
379
380         /*              Program Header                  */
381         if (verbose > 4)
382                 dprintk("\n%s:Program Header=[", __FUNCTION__);
383         for (i = 0; i < 6; i++) {
384                 hw_buffer->msg[hw_offset] = p_ca_message->msg[buf_offset];
385                 if (verbose > 4)
386                         dprintk(" %02x", p_ca_message->msg[buf_offset]);
387                 hw_offset++, buf_offset++, hw_buffer_length++;
388         }
389         if (verbose > 4)
390                 dprintk("]\n");
391
392         program_info_length = 0;
393         program_info_length = (((program_info_length | p_ca_message->msg[words + 8]) & 0x0f) << 8) | p_ca_message->msg[words + 9];
394         if (verbose > 4)
395                 dprintk("%s:Program info Length=[%d][%02x], hw_offset=[%d], buf_offset=[%d] \n",
396                         __FUNCTION__, program_info_length, program_info_length, hw_offset, buf_offset);
397
398         if (program_info_length && (program_info_length < 256)) {       /*      If program_info_length          */
399                 hw_buffer->msg[11] = hw_buffer->msg[11] & 0x0f;         /*      req only 4 bits                 */
400                 hw_buffer->msg[12] = hw_buffer->msg[12] + 1;            /*      increment! ASIC bug!            */
401
402                 if (p_ca_message->msg[buf_offset + 1] == 0x09) {        /*      Check CA descriptor             */
403                         found_prog_ca_desc = 1;
404                         if (verbose > 4)
405                                 dprintk("%s: Found CA descriptor @ Program level\n", __FUNCTION__);
406                 }
407
408                 if (found_prog_ca_desc) {                               /*      Command only if CA descriptor   */
409                         hw_buffer->msg[13] = p_ca_message->msg[buf_offset];     /*      CA PMT command ID       */
410                         hw_offset++, buf_offset++, hw_buffer_length++;
411                 }
412
413                 /*                      Program descriptors                             */
414                 if (verbose > 4) {
415                         dprintk("%s:**********>buf_offset=[%d], hw_offset=[%d]\n", __FUNCTION__, buf_offset, hw_offset);
416                         dprintk("%s:Program descriptors=[", __FUNCTION__);
417                 }
418                 while (program_info_length && !error_condition) {               /*      Copy prog descriptors   */
419                         if (program_info_length > p_ca_message->length) {       /*      Error situation         */
420                                 dprintk ("%s:\"WARNING\" Length error, line=[%d], prog_info_length=[%d]\n",
421                                                                 __FUNCTION__, __LINE__, program_info_length);
422                                 dprintk("%s:\"WARNING\" Bailing out of possible loop\n", __FUNCTION__);
423                                 error_condition = 1;
424                                 break;
425                         }
426
427                         hw_buffer->msg[hw_offset] = p_ca_message->msg[buf_offset];
428                         dprintk(" %02x", p_ca_message->msg[buf_offset]);
429                         hw_offset++, buf_offset++, hw_buffer_length++, program_info_length--;
430                 }
431                 if (verbose > 4) {
432                         dprintk("]\n");
433                         dprintk("%s:**********>buf_offset=[%d], hw_offset=[%d]\n", __FUNCTION__, buf_offset, hw_offset);
434                 }
435                 if (found_prog_ca_desc) {
436                         if (!reply) {
437                                 hw_buffer->msg[13] = 0x01;              /*      OK descrambling                 */
438                                 if (verbose > 1)
439                                         dprintk("CA PMT Command = OK Descrambling\n");
440                         }
441                         else {
442                                 hw_buffer->msg[13] = 0x02;              /*      Ok MMI                          */
443                                 if (verbose > 1)
444                                         dprintk("CA PMT Command = Ok MMI\n");
445                         }
446                         if (query) {
447                                 hw_buffer->msg[13] = 0x03;              /*      Query                           */
448                                 if (verbose > 1)
449                                         dprintk("CA PMT Command = CA PMT query\n");
450                         }
451                 }
452         }
453         else {
454                 hw_buffer->msg[11] = hw_buffer->msg[11] & 0xf0;         /*      Don't write to ASIC             */
455                 hw_buffer->msg[12] = hw_buffer->msg[12] = 0x00;
456         }
457         if (verbose > 4)
458                 dprintk("%s:**********>p_ca_message->length=[%d], buf_offset=[%d], hw_offset=[%d]\n",
459                                         __FUNCTION__, p_ca_message->length, buf_offset, hw_offset);
460
461         while ((buf_offset  < p_ca_message->length)  && !error_condition) {
462                 /*      Bail out in case of an indefinite loop          */
463                 if ((es_info_length > p_ca_message->length) || (buf_offset > p_ca_message->length)) {
464                         dprintk("%s:\"WARNING\" Length error, line=[%d], prog_info_length=[%d], buf_offset=[%d]\n",
465                                                         __FUNCTION__, __LINE__, program_info_length, buf_offset);
466
467                         dprintk("%s:\"WARNING\" Bailing out of possible loop\n", __FUNCTION__);
468                         error_condition = 1;
469                         break;
470                 }
471
472                 /*              Stream Header                           */
473
474                 for (k = 0; k < 5; k++) {
475                         hw_buffer->msg[hw_offset + k] = p_ca_message->msg[buf_offset + k];
476                 }
477
478                 es_info_length = 0;
479                 es_info_length = (es_info_length | (p_ca_message->msg[buf_offset + 3] & 0x0f)) << 8 | p_ca_message->msg[buf_offset + 4];
480
481                 if (verbose > 4) {
482                         dprintk("\n%s:----->Stream header=[%02x %02x %02x %02x %02x]\n", __FUNCTION__,
483                                 p_ca_message->msg[buf_offset + 0], p_ca_message->msg[buf_offset + 1],
484                                 p_ca_message->msg[buf_offset + 2], p_ca_message->msg[buf_offset + 3],
485                                 p_ca_message->msg[buf_offset + 4]);
486
487                         dprintk("%s:----->Stream type=[%02x], es length=[%d (0x%x)], Chars=[%02x] [%02x], buf_offset=[%d]\n", __FUNCTION__,
488                                 p_ca_message->msg[buf_offset + 0], es_info_length, es_info_length,
489                                 p_ca_message->msg[buf_offset + 3], p_ca_message->msg[buf_offset + 4], buf_offset);
490                 }
491
492                 hw_buffer->msg[hw_offset + 3] &= 0x0f;                  /*      req only 4 bits                 */
493
494                 if (found_prog_ca_desc) {
495                         hw_buffer->msg[hw_offset + 3] = 0x00;
496                         hw_buffer->msg[hw_offset + 4] = 0x00;
497                 }
498
499                 hw_offset += 5, buf_offset += 5, hw_buffer_length += 5;
500
501                 /*              Check for CA descriptor                 */
502                 if (p_ca_message->msg[buf_offset + 1] == 0x09) {
503                         if (verbose > 4)
504                                 dprintk("%s:Found CA descriptor @ Stream level\n", __FUNCTION__);
505                         found_stream_ca_desc = 1;
506                 }
507
508                 /*              ES descriptors                          */
509
510                 if (es_info_length && !error_condition && !found_prog_ca_desc && found_stream_ca_desc) {
511 //                      if (!ca_pmt_done) {
512                                 hw_buffer->msg[hw_offset] = p_ca_message->msg[buf_offset];      /*      CA PMT cmd(es)  */
513                                 if (verbose > 4)
514                                         printk("%s:----->CA PMT Command ID=[%02x]\n", __FUNCTION__, p_ca_message->msg[buf_offset]);
515 //                              hw_offset++, buf_offset++, hw_buffer_length++, es_info_length--, ca_pmt_done = 1;
516                                 hw_offset++, buf_offset++, hw_buffer_length++, es_info_length--;
517 //                      }
518                         if (verbose > 4)
519                                 dprintk("%s:----->ES descriptors=[", __FUNCTION__);
520
521                         while (es_info_length && !error_condition) {    /*      ES descriptors                  */
522                                 if ((es_info_length > p_ca_message->length) || (buf_offset > p_ca_message->length)) {
523                                         if (verbose > 4) {
524                                                 dprintk("%s:\"WARNING\" ES Length error, line=[%d], es_info_length=[%d], buf_offset=[%d]\n",
525                                                                                 __FUNCTION__, __LINE__, es_info_length, buf_offset);
526
527                                                 dprintk("%s:\"WARNING\" Bailing out of possible loop\n", __FUNCTION__);
528                                         }
529                                         error_condition = 1;
530                                         break;
531                                 }
532
533                                 hw_buffer->msg[hw_offset] = p_ca_message->msg[buf_offset];
534                                 if (verbose > 3)
535                                         dprintk("%02x ", hw_buffer->msg[hw_offset]);
536                                 hw_offset++, buf_offset++, hw_buffer_length++, es_info_length--;
537                         }
538                         found_stream_ca_desc = 0;                       /*      unset for new streams           */
539                         dprintk("]\n");
540                 }
541         }
542
543         /*              MCU Magic words                                 */
544
545         hw_buffer_length += 7;
546         hw_buffer->msg[0] = hw_buffer_length;
547         hw_buffer->msg[1] = 64;
548         hw_buffer->msg[4] = 3;
549         hw_buffer->msg[5] = hw_buffer->msg[0] - 7;
550         hw_buffer->msg[6] = 0;
551
552
553         /*      Fix length      */
554         hw_buffer->length = hw_buffer->msg[0];
555
556         put_checksum(&hw_buffer->msg[0], hw_buffer->msg[0]);
557         /*      Do the actual write     */
558         if (verbose > 4) {
559                 dprintk("%s:======================DEBUGGING================================\n", __FUNCTION__);
560                 dprintk("%s: Actual Length=[%d]\n", __FUNCTION__, hw_buffer_length);
561         }
562         /*      Only for debugging!     */
563         if (verbose > 2)
564                 debug_8820_buffer(hw_buffer);
565         if (verbose > 3)
566                 dprintk("%s: Reply = [%d]\n", __FUNCTION__, reply);
567         write_to_8820(state, hw_buffer, reply);
568
569         return 0;
570 }
571
572 /*      Board supports CA PMT reply ?           */
573 static int dst_check_ca_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer)
574 {
575         int ca_pmt_reply_test = 0;
576
577         /*      Do test board                   */
578         /*      Not there yet but soon          */
579
580
581         /*      CA PMT Reply capable            */
582         if (ca_pmt_reply_test) {
583                 if ((ca_set_pmt(state, p_ca_message, hw_buffer, 1, GET_REPLY)) < 0) {
584                         dprintk("%s: ca_set_pmt.. failed !\n", __FUNCTION__);
585                         return -1;
586                 }
587
588         /*      Process CA PMT Reply            */
589         /*      will implement soon             */
590                 dprintk("%s: Not there yet\n", __FUNCTION__);
591         }
592         /*      CA PMT Reply not capable        */
593         if (!ca_pmt_reply_test) {
594                 if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, NO_REPLY)) < 0) {
595                         dprintk("%s: ca_set_pmt.. failed !\n", __FUNCTION__);
596                         return -1;
597                 }
598                 if (verbose > 3)
599                         dprintk("%s: ca_set_pmt.. success !\n", __FUNCTION__);
600         /*      put a dummy message             */
601
602         }
603         return 0;
604 }
605
606 static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, void *arg)
607 {
608         int i = 0;
609         unsigned int ca_message_header_len;
610
611         u32 command = 0;
612         struct ca_msg *hw_buffer;
613
614         if ((hw_buffer = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) {
615                 printk("%s: Memory allocation failure\n", __FUNCTION__);
616                 return -ENOMEM;
617         }
618         if (verbose > 3)
619                 dprintk("%s\n", __FUNCTION__);
620
621         if (copy_from_user(p_ca_message, (void *)arg, sizeof (struct ca_msg)))
622                 return -EFAULT;
623
624         if (p_ca_message->msg) {
625                 ca_message_header_len = p_ca_message->length;   /*      Restore it back when you are done       */
626                 /*      EN50221 tag     */
627                 command = 0;
628
629                 for (i = 0; i < 3; i++) {
630                         command = command | p_ca_message->msg[i];
631                         if (i < 2)
632                                 command = command << 8;
633                 }
634                 if (verbose > 3)
635                         dprintk("%s:Command=[0x%x]\n", __FUNCTION__, command);
636
637                 switch (command) {
638                         case CA_PMT:
639                                 if (verbose > 3)
640                                         dprintk("Command = SEND_CA_PMT\n");
641                                 if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) {
642                                         dprintk("%s: -->CA_PMT Failed !\n", __FUNCTION__);
643                                         return -1;
644                                 }
645                                 if (verbose > 3)
646                                         dprintk("%s: -->CA_PMT Success !\n", __FUNCTION__);
647 //                              retval = dummy_set_pmt(state, p_ca_message, hw_buffer, 0, 0);
648
649                                 break;
650
651                         case CA_PMT_REPLY:
652                                 if (verbose > 3)
653                                         dprintk("Command = CA_PMT_REPLY\n");
654                                 /*      Have to handle the 2 basic types of cards here  */
655                                 if ((dst_check_ca_pmt(state, p_ca_message, hw_buffer)) < 0) {
656                                         dprintk("%s: -->CA_PMT_REPLY Failed !\n", __FUNCTION__);
657                                         return -1;
658                                 }
659                                 if (verbose > 3)
660                                         dprintk("%s: -->CA_PMT_REPLY Success !\n", __FUNCTION__);
661
662                                 /*      Certain boards do behave different ?            */
663 //                              retval = ca_set_pmt(state, p_ca_message, hw_buffer, 1, 1);
664
665                         case CA_APP_INFO_ENQUIRY:               // only for debugging
666                                 if (verbose > 3)
667                                         dprintk("%s: Getting Cam Application information\n", __FUNCTION__);
668
669                                 if ((ca_get_app_info(state)) < 0) {
670                                         dprintk("%s: -->CA_APP_INFO_ENQUIRY Failed !\n", __FUNCTION__);
671                                         return -1;
672                                 }
673                                 if (verbose > 3)
674                                         printk("%s: -->CA_APP_INFO_ENQUIRY Success !\n", __FUNCTION__);
675
676                                 break;
677                 }
678         }
679         return 0;
680 }
681
682 static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg)
683 {
684         struct dvb_device* dvbdev = (struct dvb_device*) file->private_data;
685         struct dst_state* state = (struct dst_state*) dvbdev->priv;
686         struct ca_slot_info *p_ca_slot_info;
687         struct ca_caps *p_ca_caps;
688         struct ca_msg *p_ca_message;
689
690         if ((p_ca_message = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) {
691                 printk("%s: Memory allocation failure\n", __FUNCTION__);
692                 return -ENOMEM;
693         }
694
695         if ((p_ca_slot_info = (struct ca_slot_info *) kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL)) == NULL) {
696                 printk("%s: Memory allocation failure\n", __FUNCTION__);
697                 return -ENOMEM;
698         }
699
700         if ((p_ca_caps = (struct ca_caps *) kmalloc(sizeof (struct ca_caps), GFP_KERNEL)) == NULL) {
701                 printk("%s: Memory allocation failure\n", __FUNCTION__);
702                 return -ENOMEM;
703         }
704
705         /*      We have now only the standard ioctl's, the driver is upposed to handle internals.       */
706         switch (cmd) {
707                 case CA_SEND_MSG:
708                         if (verbose > 1)
709                                 dprintk("%s: Sending message\n", __FUNCTION__);
710                         if ((ca_send_message(state, p_ca_message, arg)) < 0) {
711                                 dprintk("%s: -->CA_SEND_MSG Failed !\n", __FUNCTION__);
712                                 return -1;
713                         }
714
715                         break;
716
717                 case CA_GET_MSG:
718                         if (verbose > 1)
719                                 dprintk("%s: Getting message\n", __FUNCTION__);
720                         if ((ca_get_message(state, p_ca_message, arg)) < 0) {
721                                 dprintk("%s: -->CA_GET_MSG Failed !\n", __FUNCTION__);
722                                 return -1;
723                         }
724                         if (verbose > 1)
725                                 dprintk("%s: -->CA_GET_MSG Success !\n", __FUNCTION__);
726
727                         break;
728
729                 case CA_RESET:
730                         if (verbose > 1)
731                                 dprintk("%s: Resetting DST\n", __FUNCTION__);
732                         dst_error_bailout(state);
733                         msleep(4000);
734
735                         break;
736
737                 case CA_GET_SLOT_INFO:
738                         if (verbose > 1)
739                                 dprintk("%s: Getting Slot info\n", __FUNCTION__);
740                         if ((ca_get_slot_info(state, p_ca_slot_info, arg)) < 0) {
741                                 dprintk("%s: -->CA_GET_SLOT_INFO Failed !\n", __FUNCTION__);
742                                 return -1;
743                         }
744                         if (verbose > 1)
745                                 dprintk("%s: -->CA_GET_SLOT_INFO Success !\n", __FUNCTION__);
746
747                         break;
748
749                 case CA_GET_CAP:
750                         if (verbose > 1)
751                                 dprintk("%s: Getting Slot capabilities\n", __FUNCTION__);
752                         if ((ca_get_slot_caps(state, p_ca_caps, arg)) < 0) {
753                                 dprintk("%s: -->CA_GET_CAP Failed !\n", __FUNCTION__);
754                                 return -1;
755                         }
756                         if (verbose > 1)
757                                 dprintk("%s: -->CA_GET_CAP Success !\n", __FUNCTION__);
758
759                         break;
760
761                 case CA_GET_DESCR_INFO:
762                         if (verbose > 1)
763                                 dprintk("%s: Getting descrambler description\n", __FUNCTION__);
764                         if ((ca_get_slot_descr(state, p_ca_message, arg)) < 0) {
765                                 dprintk("%s: -->CA_GET_DESCR_INFO Failed !\n", __FUNCTION__);
766                                 return -1;
767                         }
768                         if (verbose > 1)
769                                 dprintk("%s: -->CA_GET_DESCR_INFO Success !\n", __FUNCTION__);
770
771                         break;
772
773                 case CA_SET_DESCR:
774                         if (verbose > 1)
775                                 dprintk("%s: Setting descrambler\n", __FUNCTION__);
776                         if ((ca_set_slot_descr()) < 0) {
777                                 dprintk("%s: -->CA_SET_DESCR Failed !\n", __FUNCTION__);
778                                 return -1;
779                         }
780                         if (verbose > 1)
781                                 dprintk("%s: -->CA_SET_DESCR Success !\n", __FUNCTION__);
782
783                         break;
784
785                 case CA_SET_PID:
786                         if (verbose > 1)
787                                 dprintk("%s: Setting PID\n", __FUNCTION__);
788                         if ((ca_set_pid()) < 0) {
789                                 dprintk("%s: -->CA_SET_PID Failed !\n", __FUNCTION__);
790                                 return -1;
791                         }
792                         if (verbose > 1)
793                                 dprintk("%s: -->CA_SET_PID Success !\n", __FUNCTION__);
794
795                 default:
796                         return -EOPNOTSUPP;
797                 };
798
799         return 0;
800 }
801
802 static int dst_ca_open(struct inode *inode, struct file *file)
803 {
804         if (verbose > 4)
805                 dprintk("%s:Device opened [%p]\n", __FUNCTION__, file);
806         try_module_get(THIS_MODULE);
807
808         return 0;
809 }
810
811 static int dst_ca_release(struct inode *inode, struct file *file)
812 {
813         if (verbose > 4)
814                 dprintk("%s:Device closed.\n", __FUNCTION__);
815         module_put(THIS_MODULE);
816
817         return 0;
818 }
819
820 static int dst_ca_read(struct file *file, char __user * buffer, size_t length, loff_t * offset)
821 {
822         int bytes_read = 0;
823
824         if (verbose > 4)
825                 dprintk("%s:Device read.\n", __FUNCTION__);
826
827         return bytes_read;
828 }
829
830 static int dst_ca_write(struct file *file, const char __user * buffer, size_t length, loff_t * offset)
831 {
832         if (verbose > 4)
833                 dprintk("%s:Device write.\n", __FUNCTION__);
834
835         return 0;
836 }
837
838 static struct file_operations dst_ca_fops = {
839         .owner = THIS_MODULE,
840         .ioctl = (void *)dst_ca_ioctl,
841         .open = dst_ca_open,
842         .release = dst_ca_release,
843         .read = dst_ca_read,
844         .write = dst_ca_write
845 };
846
847 static struct dvb_device dvbdev_ca = {
848         .priv = NULL,
849         .users = 1,
850         .readers = 1,
851         .writers = 1,
852         .fops = &dst_ca_fops
853 };
854
855 int dst_ca_attach(struct dst_state *dst, struct dvb_adapter *dvb_adapter)
856 {
857         struct dvb_device *dvbdev;
858         if (verbose > 4)
859                 dprintk("%s:registering DST-CA device\n", __FUNCTION__);
860         dvb_register_device(dvb_adapter, &dvbdev, &dvbdev_ca, dst, DVB_DEVICE_CA);
861         return 0;
862 }
863
864 EXPORT_SYMBOL(dst_ca_attach);
865
866 MODULE_DESCRIPTION("DST DVB-S/T/C Combo CA driver");
867 MODULE_AUTHOR("Manu Abraham");
868 MODULE_LICENSE("GPL");