[linux-dvb] Problem with init some CAM blocks on TT Budget-S1500 + CI addon

Bendyak Evgen jman at itm.net.ua
Thu Jul 19 17:11:02 CEST 2007


I have TT Budget-S1500 + CI addon, and have many CAM blocks.
So i start to test all of them on such card. And have found
that some amount of cam blocks not working on it. I know that
such card give full hw access to CAM blocks registerm and ram.
So i start to search where is problem (write small app for test
and turn on debug of dvb_core.ko in part of cam_debug=1. I found
that such CAM modules not respond on first open command Open
Transport Connection in my test app. And not answer becouse sys
function write return error with errno=EIO. So i start to debug
dvb_core.ko the write part to CAM module and detekt that function
dvb_ca_en50221_write_data in dvb_ca_en50221.c all time return in
this part:

  /* check if interface is still free */
         if ((status = ca->pub->read_cam_control(ca->pub, slot,  
CTRLIF_STATUS)) < 0)
                 goto exit;
         if (!(status & STATUSREG_FR)) {
                 /* it wasn't free => try again later */
                 status = -EAGAIN;
                 goto exit;
         }

so module do not setup flag that it ready to receive new data.
But "string dvb_ca adapter 0: DVB CAM detected and initialised  
successfully" all
times present in dmesg.
I start to read EN50221 standart in part of how init CAM and exchange data  
with it
and found intresting logical bug in dvb_ca_en50221.c.
So step by step:

 From standart:
Neither host nor module may use the interface for transferring data until  
this
protocol has completed. The host starts the negotiation by writing a '1'  
to the
SR bit in the Control Register, waiting for the DA bit to be set and then  
reading
the buffer size by a module to host transfer operation as described below.  
At
the end of the transfer operation the host resets the SR bit to '0'. The  
data
returned will be 2 bytes with the most significant byte first. Modules  
shall
support a minimum buffer size of 16 bytes. The maximum is set by the  
limitation
of the Size Register (65535 bytes). Similarly the host may have a buffer  
size
limitation that it imposes. The host shall support a minimum buffer size  
of 256
bytes but it can be up to 65535 bytes. After reading the buffer size the  
module
can support, the host takes the lower of its own buffer size and the  
module buffer
size. This will be the buffer size used for all subsequent data transfers  
between
host and module. The host now tells the module to use this buffer size by  
writing
a ?1? to the SW bit in the Command Register, waiting until the FR bit is  
set and
then writing the size as 2 bytes of data, most significant byte first,  
using the
host to module transfer operation described below. At the end of the  
transfer the
host sets the SW bit to '0'.

Host to Module Transfers:
if (Status_Reg & 0x80) /* go to module-to-host transfer (see below) */
Command_Reg = 0x01;
if (Status_Reg & 0x40) {
Size_Reg[0] = bsize & 0xFF;
Size_Reg[1] = bsize >> 8;
for (i=0; i<bsize; i++)
Data_Reg = write_buf[i];
}
Command_Reg = 0x00;

Module to Host Transfers:
if (Status_Reg & 0x80) {
bsize = Size_Reg[0] | Size_Reg[1] << 8;
for (i=0; i<bsize; i++)
read_buf[i] = Data_Reg;
}

I have found that in dvb_ca_en50221.c function dvb_ca_en50221_link_init it  
do like it
write in standart but with some small logical bug.
in this part
	/* write the buffer size to the CAM */
	if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND,  
IRQEN | CMDREG_SW)) != 0)
                 return ret;
         if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_FR,  
HZ / 10)) != 0)
                 return ret;
         if ((ret = dvb_ca_en50221_write_data(ca, slot, buf, 2)) != 2)
                 return -EIO;
         if ((ret = ca->pub->write_cam_control(ca->pub, slot,  
CTRLIF_COMMAND, IRQEN)) != 0)
                 return ret;

it setup SW bit like in standart wait untill FR is set and call write_data  
but inside of
dvb_ca_en50221_write_data COMMAND register setuped to (IRQEN | CMDREG_HC)  
and bit SW now is 0
but by standart it must be holded 1 untill full end of setup buffer size  
operation.
So module on next try of write to it not setup FR flag bit becouse it wait  
till finishing of init
part.
So i make dublicate of dvb_ca_en50221_write_data and call it
static int dvb_ca_en50221_write_data_with_flag(struct dvb_ca_private *ca,  
int slot, u8 * ebuf, int ecount,u8 AddFlag); it have parameter AddFlag  
witch used in write data to COMMAND register (IRQEN | CMDREG_HC | AddFlag)
and call this function inside of dvb_ca_en50221_link_init insted of  
dvb_ca_en50221_write_data
not it looks:
if ((ret = dvb_ca_en50221_write_data_with_flag(ca, slot, buf,  
2,CMDREG_SW)) != 2)
      return -EIO;
So most of modules start to work with such modification buta few modules  
still not return that
it ready to recive data in write function after dvb_ca_en50221_link_init.
I start to search meaning of IRQEN by definition inside of  
dvb_ca_en50221.c it is 7 and 6 bit
but in standart this bits is reserved and must by in 0.

So i modiffy more dvb_ca_en50221_link_init and  
dvb_ca_en50221_write_data_with_flag and disable from
it IRQEN. and only setup it at end of init sequence. After this  
modification it start ti work with
all CAM modules that i have.

So i have question: what is meaning IRQEN bits? As i understand enable  
some interrupt request
on send & receive but in EN50221 modules do not use interrupts in must be  
only polled for
new data present by DA bit in STATUS register.

diff file of modification:

--- dvb_ca_en50221.c	2007-07-19 17:10:18.000000000 +0300
+++ dvb_ca_en50221.c	2007-07-19 08:29:49.000000000 +0300
@@ -1,6 +1,9 @@
  /*
   * dvb_ca.c: generic DVB functions for EN50221 CAM interfaces
   *
+ *
+ * Copyright (C) 2007 Evgen Bendyak (modification of cam initialization  
in part of write host buffer size)
+ *
   * Copyright (C) 2004 Andrew de Quincey
   *
   * Parts of this file were based on sources as follows:
@@ -164,6 +167,7 @@
  static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca);
  static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot,  
u8 * ebuf, int ecount);
  static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot,  
u8 * ebuf, int ecount);
+static int dvb_ca_en50221_write_data_with_flag(struct dvb_ca_private *ca,  
int slot, u8 * ebuf, int ecount,u8 AddFlag);


  /**
@@ -313,17 +317,18 @@
  	ca->slot_info[slot].link_buf_size = 2;

  	/* read the buffer size from the CAM */
-	if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND,  
IRQEN | CMDREG_SR)) != 0)
+	if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND,  
CMDREG_SR)) != 0)
  		return ret;
  	if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_DA, HZ /  
10)) != 0)
  		return ret;
  	if ((ret = dvb_ca_en50221_read_data(ca, slot, buf, 2)) != 2)
  		return -EIO;
-	if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND,  
IRQEN)) != 0)
+	if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, 0))  
!= 0)
  		return ret;

  	/* store it, and choose the minimum of our buffer and the CAM's buffer  
size */
  	buf_size = (buf[0] << 8) | buf[1];
@@ -332,11 +337,11 @@
  	dprintk("Chosen link buffer size of %i\n", buf_size);

  	/* write the buffer size to the CAM */
-	if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND,  
IRQEN | CMDREG_SW)) != 0)
+	if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND,  
CMDREG_SW)) != 0)
  		return ret;
  	if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_FR, HZ /  
10)) != 0)
  		return ret;
-	if ((ret = dvb_ca_en50221_write_data(ca, slot, buf, 2)) != 2)
+	if ((ret = dvb_ca_en50221_write_data_with_flag(ca, slot, buf,  
2,CMDREG_SW)) != 2)
  		return -EIO;
  	if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND,  
IRQEN)) != 0)
  		return ret;
@@ -775,6 +780,87 @@
  exitnowrite:
  	return status;
  }
+
+/**
+ * This function talks to an EN50221 CAM control interface (but with some  
additional
+ * bits setuped in CTRLIF_COMMAND register and without IRQEN). Used in  
setup exchange
+ * buffer size sequence
+ * It writes a buffer of data to a CAM.
+ *
+ * @param ca CA instance.
+ * @param slot Slot to write to.
+ * @param ebuf The data in this buffer is treated as a complete  
link-level packet to
+ * be written.
+ * @param count Size of ebuf.
+ *
+ * @return Number of bytes written, or < 0 on error.
+ */
+static int dvb_ca_en50221_write_data_with_flag(struct dvb_ca_private *ca,  
int slot, u8 * buf, int bytes_write,u8 AddFlags)
+{
+	int status;
+	int i;
+
+	dprintk("%s\n", __FUNCTION__);
+
+
+	// sanity check
+	if (bytes_write > ca->slot_info[slot].link_buf_size)
+		return -EINVAL;
+
+	/* check if interface is actually waiting for us to read from it, or if  
a read is in progress */
+	if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) <  
0)
+		goto exitnowrite;
+	if (status & (STATUSREG_DA | STATUSREG_RE)) {
+		status = -EAGAIN;
+		goto exitnowrite;
+	}
+
+	/* OK, set HC bit */
+	if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND,
+						 CMDREG_HC | AddFlags)) != 0)
+		goto exit;
+
+	/* check if interface is still free */
+	if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) <  
0)
+		goto exit;
+	if (!(status & STATUSREG_FR)) {
+		/* it wasn't free => try again later */
+		status = -EAGAIN;
+		goto exit;
+	}
+
+	/* send the amount of data */
+	if ((status = ca->pub->write_cam_control(ca->pub, slot,  
CTRLIF_SIZE_HIGH, bytes_write >> 8)) != 0)
+		goto exit;
+	if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW,
+						 bytes_write & 0xff)) != 0)
+		goto exit;
+
+	/* send the buffer */
+	for (i = 0; i < bytes_write; i++) {
+		if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_DATA,  
buf[i])) != 0)
+			goto exit;
+	}
+
+	/* check for write error (WE should now be 0) */
+	if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) <  
0)
+		goto exit;
+	if (status & STATUSREG_WE) {
+		ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
+		status = -EIO;
+		goto exit;
+	}
+	status = bytes_write;
+
+	dprintk("Wrote CA packet for slot %i, connection id 0x%x last_frag:%i  
size:0x%x\n", slot,
+		buf[0], (buf[1] & 0x80) == 0, bytes_write);
+
+exit:
+	ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, AddFlags);
+
+exitnowrite:
+	return status;
+}
  EXPORT_SYMBOL(dvb_ca_en50221_camchange_irq);



Evgen Bendyak
Kiev. Ukraine.



More information about the linux-dvb mailing list