Hi, Today, application info can be enquired from the dst_ca ca using the ioctl CA_APP_INFO_ENQUIRY. However, the answer which is returned is the raw data of the answer from the HW and not formatted as described in EN-50221. (Which is probably why there is a "only for debugging"-comment in the code). I have made patch which 1. Restructures the answer from CA_APP_INFO_ENQUIRY to conform with application_info (EN50221:1997, p.28). 2. Adds support for CA Info Enquiry, conforming to EN50221:1997, p.29. Since this will break dst_test -a, a patch is also needed for dvb-apps to correct dst_test for application info and add support for ca info. It would be great if anyone more familiar with the specs. could take a look at it and see if it looks ok. It would also be good to have some testing from some Twinhan CI-card users as well. Regards, Henrik First, the patch for the driver (v4l-dvb): Signed-off-by: Henrik Sj?berg <henke@xxxxxxxx> Index: linux/drivers/media/dvb/bt8xx/dst_ca.c =================================================================== RCS file: /cvs/video4linux/v4l-dvb/linux/drivers/media/dvb/bt8xx/dst_ca.c,v retrieving revision 1.19 diff -p -u -b -r1.19 dst_ca.c --- linux/drivers/media/dvb/bt8xx/dst_ca.c 27 Dec 2005 00:43:05 -0000 1.19 +++ linux/drivers/media/dvb/bt8xx/dst_ca.c 9 Jan 2006 12:57:29 -0000 @@ -141,6 +144,7 @@ static int dst_put_ci(struct dst_state * static int ca_get_app_info(struct dst_state *state) { static u8 command[8] = {0x07, 0x40, 0x01, 0x00, 0x01, 0x00, 0x00, 0xff}; + int i, length, str_length; put_checksum(&command[0], command[0]); if ((dst_put_ci(state, command, sizeof(command), state->messages, GET_REPLY)) < 0) { @@ -154,6 +158,72 @@ static int ca_get_app_info(struct dst_st (state->messages[10] << 8) | state->messages[11], __FUNCTION__, (char *)(&state->messages[12])); dprintk(verbose, DST_CA_INFO, 1, " ========================================================================= ========================="); + // Transform dst message to correct application_info message + // according to EN50221 + length = state->messages[5]; + str_length = length - 6; + + // First, the command and length fields + state->messages[0] = (CA_APP_INFO >> 16) & 0xff; + state->messages[1] = (CA_APP_INFO >> 8) & 0xff; + state->messages[2] = CA_APP_INFO & 0xff; + state->messages[3] = length; + + // Copy application_type, application_manufacturer and manufacturer_code + for (i = 0; i < 5; i++) { + state->messages[i + 4] = state->messages[i + 7]; + } + + // Set string length and copy string + state->messages[9] = str_length; + for (i = 0; i < length; i++) { + state->messages[10 + i] = state->messages[12 + i]; + } + + return 0; +} + +static int ca_get_ca_info(struct dst_state *state) +{ + int srcPtr, dstPtr, i, num_ids; + static u8 slot_command[8] = {0x07, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, 0xff}; + const int in_system_id_pos = 8, out_system_id_pos = 4, in_num_ids_pos = 7; + + put_checksum(&slot_command[0], slot_command[0]); + if ((dst_put_ci(state, slot_command, sizeof (slot_command), state->messages, GET_REPLY)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); + return -1; + } + dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !"); + + // Print raw data + dprintk(verbose, DST_CA_INFO, 0, " DST data = ["); + for (i = 0; i < state->messages[0] + 1; i++) { + dprintk(verbose, DST_CA_INFO, 0, " 0x%02x", state->messages[i]); + } + dprintk(verbose, DST_CA_INFO, 1, "]\n"); + + // Set the command and length of the output + num_ids = state->messages[in_num_ids_pos]; + state->messages[0] = (CA_INFO >> 16) & 0xff; + state->messages[1] = (CA_INFO >> 8) & 0xff; + state->messages[2] = CA_INFO & 0xff; + state->messages[3] = num_ids * 2; + + // Print and copy the system ids + dprintk(verbose, DST_CA_INFO, 0, " CA_INFO = ["); + srcPtr = in_system_id_pos; + dstPtr = out_system_id_pos; + for(i = 0; i < num_ids; i++) { + dprintk(verbose, DST_CA_INFO, 0, " 0x%02x%02x", state->messages[srcPtr + 0], state->messages[srcPtr + 1]); + // Append to output + state->messages[dstPtr + 0] = state->messages[srcPtr + 0]; + state->messages[dstPtr + 1] = state->messages[srcPtr + 1]; + srcPtr += 2; + dstPtr += 2; + } + dprintk(verbose, DST_CA_INFO, 0, "]\n"); + return 0; } @@ -174,7 +244,7 @@ static int ca_get_slot_caps(struct dst_s dprintk(verbose, DST_CA_INFO, 1, " Slot cap = [%d]", slot_cap[7]); dprintk(verbose, DST_CA_INFO, 0, "===================================\n"); - for (i = 0; i < 8; i++) + for (i = 0; i < slot_cap[0] + 1; i++) dprintk(verbose, DST_CA_INFO, 0, " %d", slot_cap[i]); dprintk(verbose, DST_CA_INFO, 0, "\n"); @@ -260,6 +330,11 @@ static int ca_get_message(struct dst_sta if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) ) return -EFAULT; break; + case CA_INFO: + memcpy(p_ca_message->msg, state->messages, 128); + if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) ) + return -EFAULT; + break; } } @@ -302,7 +377,7 @@ static int write_to_8820(struct dst_stat rdc_reset_state(state); return -1; } - dprintk(verbose, DST_CA_NOTICE, 1, " DST-CI Command succes."); + dprintk(verbose, DST_CA_NOTICE, 1, " DST-CI Command success."); return 0; } @@ -455,6 +530,16 @@ static int ca_send_message(struct dst_st } dprintk(verbose, DST_CA_INFO, 1, " -->CA_APP_INFO_ENQUIRY Success !"); break; + case CA_INFO_ENQUIRY: + dprintk(verbose, DST_CA_INFO, 1, " Getting Cam CA information"); + + if ((ca_get_ca_info(state)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_INFO_ENQUIRY Failed !"); + result = -1; + goto free_mem_and_exit; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_INFO_ENQUIRY Success !"); + break; } } free_mem_and_exit: Second, the patch for dvb-apps: Index: util/dst-utils/dst_test.c =================================================================== RCS file: /cvs/linuxtv/dvb-apps/util/dst-utils/dst_test.c,v retrieving revision 1.1 diff -p -u -b -r1.1 dst_test.c --- util/dst-utils/dst_test.c 22 Jun 2005 16:10:25 -0000 1.1 +++ util/dst-utils/dst_test.c 9 Jan 2006 13:02:41 -0000 @@ -160,15 +160,51 @@ static int dst_get_app_info(int cafd, st } /* Process */ + // Make sure we are null terminated + msg->msg[10 + msg->msg[9]] = 0; + + printf("\n"); printf("%s: ================================ CI Module Application Info ==================================== ==\n", __FUNCTION__); printf("%s: Application Type=[%d], Application Vendor=[%d], Vendor Code=[%d]\n%s: Application info=[%s]\n", - __FUNCTION__, msg->msg[7], (msg->msg[8] << 8) | msg->msg[9], (msg->msg[10] << 8) | msg->msg[ 11], __FUNCTION__, - ((char *) (&msg->msg[12]))); + __FUNCTION__, msg->msg[4], (msg->msg[5] << 8) | msg->msg[6], (msg->msg[7] << 8) | msg->msg[8], __FUNC TION__, + ((char *) (&msg->msg[10]))); printf("%s: ================================================================================================ ==\n", __FUNCTION__); return 0; } +static int dst_get_ca_info(int cafd, struct ca_msg *msg) +{ + uint32_t tag = 0; + int ptr = 4; + + /* Enquire */ + tag = CA_INFO_ENQUIRY; + if ((dst_comms(cafd, tag, CA_SEND_MSG, msg)) < 0) { + printf("%s: Dst communication failed\n", __FUNCTION__); + return -1; + } + + /* Receive */ + tag = CA_INFO; + if ((dst_comms(cafd, tag, CA_GET_MSG, msg)) < 0) { + printf("%s: Dst communication failed\n", __FUNCTION__); + return -1; + } + + /* Process */ + printf("%s: ================================ CI Module CA Info ======================================\n", __ FUNCTION__); + printf("%s: CA System IDs=[", __FUNCTION__); + + while (ptr < (msg->msg[3] + 4)) { + printf("0x%02x%02x ", msg->msg[ptr + 0], msg->msg[ptr + 1]); + ptr += 2; + } + printf("]\n%s: ============================================================================================= =====\n", __FUNCTION__); + + return 0; +} + static int dst_session_test(int cafd, struct ca_msg *msg) { msg->msg[0] = 0x91; @@ -196,7 +232,8 @@ int main(int argc, char *argv[]) "\t -g get descr\n" "\t -s set_descr\n" "\t -a app_info\n" - "\t -t session test\n"; + "\t -t session test\n" + "\t -b ca_info\n"; struct ca_caps *caps; @@ -217,7 +254,7 @@ int main(int argc, char *argv[]) return -1; } - switch (getopt(argc, argv, "cirpgsat")) { + switch (getopt(argc, argv, "cirpgsatb")) { case 'c': printf("%s: Capabilities\n", __FUNCTION__); dst_get_caps(cafd, caps); @@ -246,6 +283,10 @@ int main(int argc, char *argv[]) printf("%s: App Info\n", __FUNCTION__); dst_get_app_info(cafd, msg); break; + case 'b': + printf("%s: CA Info\n", __FUNCTION__); + dst_get_ca_info(cafd, msg); + break; case 't': printf("%s: Session test\n", __FUNCTION__); dst_session_test(cafd, msg);