All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/7] Add block read/write to en50221 CAM functions
@ 2017-06-25 21:37 Jasmin J.
  2017-06-25 21:37 ` [PATCH v2 1/7] [media] dvb-core/dvb_ca_en50221.c: State UNINITIALISED instead of INVALID Jasmin J.
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Jasmin J. @ 2017-06-25 21:37 UTC (permalink / raw)
  To: linux-media; +Cc: mchehab, max.kellermann, rjkm, d.scheller, jasmin

From: Jasmin Jessich <jasmin@anw.at>

This is now the V2 version of the patch series with preserved author and
little checkpatch fixes. I also combined some patches which needs to be
applied at once to.

Changes from v1 to v2:
 - Preserved authorship of original author.
 - All patches tested with checkpatch.pl (no errors).
 - Patch "Set maximum cxd2099 block size to 512" is now part of patch
   "Fixed buffer mode", because this needs to be applied together.
 - Patch "Removed useless printing in cxd2099 driver" is now split into a
   part which is already upstream and an additional one.
 - Rebased to media_tree/master.
 
These patch series implement a block read/write interface to the en50221
CAM control functions. The origin of this patches can be found in the
Digital Devices Git on https://github.com/DigitalDevices/dddvb maintained
by Ralph Metzler <rjkm@metzlerbros.de> .
 
The relevant changes concerning dvb-core/dvb_ca_en50221.c/.h and
cxd2099/cxd2099.c/.h have been extracted from the mentioned repository by
Daniel Scheller <d.scheller@gmx.net> and committed to his branch on
https://github.com/herrnst/dddvb-linux-kernel/tree/mediatree/master-cxd2099
 
I split the patch set in smaller pieces for easier review, fixed code style
issues in cxd2099/cxd2099.c/.h and dvb_ca_en50221.c (checkpatch.pl) and
tested the resulting driver on my hardware with the DD DuoFlex CI (single)
card. I tested if the CAM communication is working with VDR:
 vdr: [2414] CAM 1: module ready
 vdr: [2414] CAM 1: AlphaCrypt, 01, 4A20, 4A20
 vdr: [2414] CAM 1: system ids: 0D95 0648 1702 1722 1762 4A20 0500 0B00
                                0100 1833 1834 0D05 0D22
 vdr: [2414] CAM 1: replies to QUERY - multi channel decryption (MCD)
                    possible
 vdr: [2414] CAM 1: supports multi transponder decryption (MTD)
 vdr: [2414] CAM 1: activating MTD support
 vdr: [2405] CAM 1: ready, master (AlphaCrypt)

Please note, that the block read/write functionality is already implemented
in the currently existing cxd2099/cxd2099.c/.h driver, but deactivated. The
existing code in this driver is also not functional and has been updated by
the working implementation from the Digital Devices Git.
 
Additionally to the block read/write functions, I merged also two patches
in the en50221 CAM control state machine, which were existing in the
Digital Devices Git. This are the first two patches of this series.
 
There is another patch series coming "Fix coding style in en50221 CAM
functions" which fixes some of the style issues in
dvb-core/dvb_ca_en50221.c/.h, based on this patch series. I will send this
after this series has been accepted.

Jasmin Jessich (2):
  [staging] cxd2099/cxd2099.c: Removed printing in write_block
  [staging] cxd2099/cxd2099.c: Activate cxd2099 buffer mode

Ralph Metzler (5):
  [media] dvb-core/dvb_ca_en50221.c: State UNINITIALISED instead of
    INVALID
  [media] dvb-core/dvb_ca_en50221.c: Increase timeout for link init
  [media] dvb-core/dvb_ca_en50221.c: Add block read/write functions
  [staging] cxd2099/cxd2099.c/.h: Fixed buffer mode
  [staging] cxd2099/cxd2099.c: Removed useless printing in cxd2099
    driver

 drivers/media/dvb-core/dvb_ca_en50221.c    | 143 +++++++++++++++----------
 drivers/media/dvb-core/dvb_ca_en50221.h    |   7 ++
 drivers/media/pci/ddbridge/ddbridge-core.c |   1 +
 drivers/staging/media/cxd2099/cxd2099.c    | 165 ++++++++++++++++++++---------
 drivers/staging/media/cxd2099/cxd2099.h    |   6 +-
 5 files changed, 217 insertions(+), 105 deletions(-)

-- 
2.7.4

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v2 1/7] [media] dvb-core/dvb_ca_en50221.c: State UNINITIALISED instead of INVALID
  2017-06-25 21:37 [PATCH v2 0/7] Add block read/write to en50221 CAM functions Jasmin J.
@ 2017-06-25 21:37 ` Jasmin J.
  2017-06-25 21:37 ` [PATCH v2 2/7] [media] dvb-core/dvb_ca_en50221.c: Increase timeout for link init Jasmin J.
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Jasmin J. @ 2017-06-25 21:37 UTC (permalink / raw)
  To: linux-media; +Cc: mchehab, max.kellermann, rjkm, d.scheller, jasmin

From: Ralph Metzler <rjkm@metzlerbros.de>

In case of a linkinit failure change to state UNINITIALISED to re-init
the CAM.

Original code change by Ralph Metzler, modified by Jasmin Jessich to match
Kernel code style.

Signed-off-by: Ralph Metzler <rjkm@metzlerbros.de>
Signed-off-by: Jasmin Jessich <jasmin@anw.at>
---
 drivers/media/dvb-core/dvb_ca_en50221.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/media/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb-core/dvb_ca_en50221.c
index af694f2..80edbe8 100644
--- a/drivers/media/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb-core/dvb_ca_en50221.c
@@ -1176,7 +1176,8 @@ static int dvb_ca_en50221_thread(void *data)
 
 					pr_err("dvb_ca adapter %d: DVB CAM link initialisation failed :(\n",
 					       ca->dvbdev->adapter->num);
-					ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+					ca->slot_info[slot].slot_state =
+						DVB_CA_SLOTSTATE_UNINITIALISED;
 					dvb_ca_en50221_thread_update_delay(ca);
 					break;
 				}
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 2/7] [media] dvb-core/dvb_ca_en50221.c: Increase timeout for link init
  2017-06-25 21:37 [PATCH v2 0/7] Add block read/write to en50221 CAM functions Jasmin J.
  2017-06-25 21:37 ` [PATCH v2 1/7] [media] dvb-core/dvb_ca_en50221.c: State UNINITIALISED instead of INVALID Jasmin J.
@ 2017-06-25 21:37 ` Jasmin J.
  2017-06-25 21:37 ` [PATCH v2 3/7] [media] dvb-core/dvb_ca_en50221.c: Add block read/write functions Jasmin J.
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Jasmin J. @ 2017-06-25 21:37 UTC (permalink / raw)
  To: linux-media; +Cc: mchehab, max.kellermann, rjkm, d.scheller, jasmin

From: Ralph Metzler <rjkm@metzlerbros.de>

Some CAMs do a really slow initialization, which requires a longer timeout
for the first response.

Original code change by Ralph Metzler, modified by Jasmin Jessich to match
Kernel code style.

Signed-off-by: Ralph Metzler <rjkm@metzlerbros.de>
Signed-off-by: Jasmin Jessich <jasmin@anw.at>
---
 drivers/media/dvb-core/dvb_ca_en50221.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/media/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb-core/dvb_ca_en50221.c
index 80edbe8..529e7ec 100644
--- a/drivers/media/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb-core/dvb_ca_en50221.c
@@ -349,7 +349,8 @@ static int dvb_ca_en50221_link_init(struct dvb_ca_private *ca, int slot)
 	/* read the buffer size from the CAM */
 	if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SR)) != 0)
 		return ret;
-	if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_DA, HZ / 10)) != 0)
+	ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_DA, HZ);
+	if (ret != 0)
 		return ret;
 	if ((ret = dvb_ca_en50221_read_data(ca, slot, buf, 2)) != 2)
 		return -EIO;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 3/7] [media] dvb-core/dvb_ca_en50221.c: Add block read/write functions
  2017-06-25 21:37 [PATCH v2 0/7] Add block read/write to en50221 CAM functions Jasmin J.
  2017-06-25 21:37 ` [PATCH v2 1/7] [media] dvb-core/dvb_ca_en50221.c: State UNINITIALISED instead of INVALID Jasmin J.
  2017-06-25 21:37 ` [PATCH v2 2/7] [media] dvb-core/dvb_ca_en50221.c: Increase timeout for link init Jasmin J.
@ 2017-06-25 21:37 ` Jasmin J.
  2017-06-25 21:37 ` [PATCH v2 4/7] [staging] cxd2099/cxd2099.c/.h: Fixed buffer mode Jasmin J.
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Jasmin J. @ 2017-06-25 21:37 UTC (permalink / raw)
  To: linux-media; +Cc: mchehab, max.kellermann, rjkm, d.scheller, jasmin

From: Ralph Metzler <rjkm@metzlerbros.de>

Some lower level drivers may work better when sending blocks of data
instead byte per byte. For this we need new function pointers in the
dvb_ca_en50221 protocol structure (read_data, write_data) and the protocol
needs to execute them, if they are defined.
Block data transmission is done in all states except LINKINIT.

Original code change by Ralph Metzler, modified by Jasmin Jessich and
Daniel Scheller to match Kernel code style.

Signed-off-by: Ralph Metzler <rjkm@metzlerbros.de>
Signed-off-by: Daniel Scheller <d.scheller@gmx.net>
Signed-off-by: Jasmin Jessich <jasmin@anw.at>
---
 drivers/media/dvb-core/dvb_ca_en50221.c | 137 ++++++++++++++++++++------------
 drivers/media/dvb-core/dvb_ca_en50221.h |   7 ++
 2 files changed, 92 insertions(+), 52 deletions(-)

diff --git a/drivers/media/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb-core/dvb_ca_en50221.c
index 529e7ec..17970cd 100644
--- a/drivers/media/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb-core/dvb_ca_en50221.c
@@ -645,72 +645,101 @@ static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot,
 		}
 		buf_free = dvb_ringbuffer_free(&ca->slot_info[slot].rx_buffer);
 
-		if (buf_free < (ca->slot_info[slot].link_buf_size + DVB_RINGBUFFER_PKTHDRSIZE)) {
+		if (buf_free < (ca->slot_info[slot].link_buf_size +
+				DVB_RINGBUFFER_PKTHDRSIZE)) {
 			status = -EAGAIN;
 			goto exit;
 		}
 	}
 
-	/* check if there is data available */
-	if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
-		goto exit;
-	if (!(status & STATUSREG_DA)) {
-		/* no data */
-		status = 0;
-		goto exit;
-	}
-
-	/* read the amount of data */
-	if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH)) < 0)
-		goto exit;
-	bytes_read = status << 8;
-	if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW)) < 0)
-		goto exit;
-	bytes_read |= status;
+	if (ca->pub->read_data &&
+	    (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_LINKINIT)) {
+		if (ebuf == NULL)
+			status = ca->pub->read_data(ca->pub, slot, buf,
+						    sizeof(buf));
+		else
+			status = ca->pub->read_data(ca->pub, slot, buf, ecount);
+		if (status < 0)
+			return status;
+		bytes_read =  status;
+		if (status == 0)
+			goto exit;
+	} else {
 
-	/* check it will fit */
-	if (ebuf == NULL) {
-		if (bytes_read > ca->slot_info[slot].link_buf_size) {
-			pr_err("dvb_ca adapter %d: CAM tried to send a buffer larger than the link buffer size (%i > %i)!\n",
-			       ca->dvbdev->adapter->num, bytes_read,
-			       ca->slot_info[slot].link_buf_size);
-			ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
-			status = -EIO;
+		/* check if there is data available */
+		status = ca->pub->read_cam_control(ca->pub, slot,
+						   CTRLIF_STATUS);
+		if (status < 0)
 			goto exit;
-		}
-		if (bytes_read < 2) {
-			pr_err("dvb_ca adapter %d: CAM sent a buffer that was less than 2 bytes!\n",
-			       ca->dvbdev->adapter->num);
-			ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
-			status = -EIO;
+		if (!(status & STATUSREG_DA)) {
+			/* no data */
+			status = 0;
 			goto exit;
 		}
-	} else {
-		if (bytes_read > ecount) {
-			pr_err("dvb_ca adapter %d: CAM tried to send a buffer larger than the ecount size!\n",
-			       ca->dvbdev->adapter->num);
-			status = -EIO;
+
+		/* read the amount of data */
+		status = ca->pub->read_cam_control(ca->pub, slot,
+						   CTRLIF_SIZE_HIGH);
+		if (status < 0)
+			goto exit;
+		bytes_read = status << 8;
+		status = ca->pub->read_cam_control(ca->pub, slot,
+						   CTRLIF_SIZE_LOW);
+		if (status < 0)
 			goto exit;
+		bytes_read |= status;
+
+		/* check it will fit */
+		if (ebuf == NULL) {
+			if (bytes_read > ca->slot_info[slot].link_buf_size) {
+				pr_err("dvb_ca adapter %d: CAM tried to send a buffer larger than the link buffer size (%i > %i)!\n",
+				       ca->dvbdev->adapter->num, bytes_read,
+				       ca->slot_info[slot].link_buf_size);
+				ca->slot_info[slot].slot_state =
+						     DVB_CA_SLOTSTATE_LINKINIT;
+				status = -EIO;
+				goto exit;
+			}
+			if (bytes_read < 2) {
+				pr_err("dvb_ca adapter %d: CAM sent a buffer that was less than 2 bytes!\n",
+				       ca->dvbdev->adapter->num);
+				ca->slot_info[slot].slot_state =
+						     DVB_CA_SLOTSTATE_LINKINIT;
+				status = -EIO;
+				goto exit;
+			}
+		} else {
+			if (bytes_read > ecount) {
+				pr_err("dvb_ca adapter %d: CAM tried to send a buffer larger than the ecount size!\n",
+				       ca->dvbdev->adapter->num);
+				status = -EIO;
+				goto exit;
+			}
 		}
-	}
 
-	/* fill the buffer */
-	for (i = 0; i < bytes_read; i++) {
-		/* read byte and check */
-		if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_DATA)) < 0)
-			goto exit;
+		/* fill the buffer */
+		for (i = 0; i < bytes_read; i++) {
+			/* read byte and check */
+			status = ca->pub->read_cam_control(ca->pub, slot,
+							   CTRLIF_DATA);
+			if (status < 0)
+				goto exit;
 
-		/* OK, store it in the buffer */
-		buf[i] = status;
-	}
+			/* OK, store it in the buffer */
+			buf[i] = status;
+		}
 
-	/* check for read error (RE should now be 0) */
-	if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
-		goto exit;
-	if (status & STATUSREG_RE) {
-		ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
-		status = -EIO;
-		goto exit;
+		/* check for read error (RE should now be 0) */
+		status = ca->pub->read_cam_control(ca->pub, slot,
+						   CTRLIF_STATUS);
+		if (status < 0)
+			goto exit;
+		if (status & STATUSREG_RE) {
+			ca->slot_info[slot].slot_state =
+						     DVB_CA_SLOTSTATE_LINKINIT;
+			status = -EIO;
+			goto exit;
+		}
 	}
 
 	/* OK, add it to the receive buffer, or copy into external buffer if supplied */
@@ -763,6 +792,10 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot,
 	if (bytes_write > ca->slot_info[slot].link_buf_size)
 		return -EINVAL;
 
+	if (ca->pub->write_data &&
+	    (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_LINKINIT))
+		return ca->pub->write_data(ca->pub, slot, buf, bytes_write);
+
 	/* it is possible we are dealing with a single buffer implementation,
 	   thus if there is data available for read or if there is even a read
 	   already in progress, we do nothing but awake the kernel thread to
diff --git a/drivers/media/dvb-core/dvb_ca_en50221.h b/drivers/media/dvb-core/dvb_ca_en50221.h
index 1e4bbbd..82617ba 100644
--- a/drivers/media/dvb-core/dvb_ca_en50221.h
+++ b/drivers/media/dvb-core/dvb_ca_en50221.h
@@ -41,6 +41,8 @@
  * @write_attribute_mem: function for writing attribute memory on the CAM
  * @read_cam_control:	function for reading the control interface on the CAM
  * @write_cam_control:	function for reading the control interface on the CAM
+ * @read_data:		function for reading data (block mode)
+ * @write_data:		function for writing data (block mode)
  * @slot_reset:		function to reset the CAM slot
  * @slot_shutdown:	function to shutdown a CAM slot
  * @slot_ts_enable:	function to enable the Transport Stream on a CAM slot
@@ -66,6 +68,11 @@ struct dvb_ca_en50221 {
 	int (*write_cam_control)(struct dvb_ca_en50221 *ca,
 				 int slot, u8 address, u8 value);
 
+	int (*read_data)(struct dvb_ca_en50221 *ca,
+				int slot, u8 *ebuf, int ecount);
+	int (*write_data)(struct dvb_ca_en50221 *ca,
+				int slot, u8 *ebuf, int ecount);
+
 	int (*slot_reset)(struct dvb_ca_en50221 *ca, int slot);
 	int (*slot_shutdown)(struct dvb_ca_en50221 *ca, int slot);
 	int (*slot_ts_enable)(struct dvb_ca_en50221 *ca, int slot);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 4/7] [staging] cxd2099/cxd2099.c/.h: Fixed buffer mode
  2017-06-25 21:37 [PATCH v2 0/7] Add block read/write to en50221 CAM functions Jasmin J.
                   ` (2 preceding siblings ...)
  2017-06-25 21:37 ` [PATCH v2 3/7] [media] dvb-core/dvb_ca_en50221.c: Add block read/write functions Jasmin J.
@ 2017-06-25 21:37 ` Jasmin J.
  2017-06-25 21:37 ` [PATCH v2 5/7] [staging] cxd2099/cxd2099.c: Removed useless printing in cxd2099 driver Jasmin J.
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Jasmin J. @ 2017-06-25 21:37 UTC (permalink / raw)
  To: linux-media; +Cc: mchehab, max.kellermann, rjkm, d.scheller, jasmin

From: Ralph Metzler <rjkm@metzlerbros.de>

The buffer mode was already implemented in this driver, but it did not work
as expected. This has been fixed now, but it is still deactivated and can
be activated by removing a comment at the begin of the file.

Original code change by Ralph Metzler, modified by Jasmin Jessich and
Daniel Scheller to match Kernel code style.

Signed-off-by: Ralph Metzler <rjkm@metzlerbros.de>
Signed-off-by: Daniel Scheller <d.scheller@gmx.net>
Signed-off-by: Jasmin Jessich <jasmin@anw.at>
---
 drivers/media/pci/ddbridge/ddbridge-core.c |   1 +
 drivers/staging/media/cxd2099/cxd2099.c    | 162 +++++++++++++++++++++--------
 drivers/staging/media/cxd2099/cxd2099.h    |   6 +-
 3 files changed, 123 insertions(+), 46 deletions(-)

diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c
index 32f4d37..cd1723e 100644
--- a/drivers/media/pci/ddbridge/ddbridge-core.c
+++ b/drivers/media/pci/ddbridge/ddbridge-core.c
@@ -1305,6 +1305,7 @@ static struct cxd2099_cfg cxd_cfg = {
 	.adr     =  0x40,
 	.polarity = 1,
 	.clock_mode = 1,
+	.max_i2c = 512,
 };
 
 static int ddb_ci_attach(struct ddb_port *port)
diff --git a/drivers/staging/media/cxd2099/cxd2099.c b/drivers/staging/media/cxd2099/cxd2099.c
index 370ecb9..60d8dd0 100644
--- a/drivers/staging/media/cxd2099/cxd2099.c
+++ b/drivers/staging/media/cxd2099/cxd2099.c
@@ -1,7 +1,7 @@
 /*
  * cxd2099.c: Driver for the CXD2099AR Common Interface Controller
  *
- * Copyright (C) 2010-2011 Digital Devices GmbH
+ * Copyright (C) 2010-2013 Digital Devices GmbH
  *
  *
  * This program is free software; you can redistribute it and/or
@@ -33,7 +33,9 @@
 
 #include "cxd2099.h"
 
-#define MAX_BUFFER_SIZE 248
+/* #define BUFFER_MODE 1 */
+
+static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount);
 
 struct cxd {
 	struct dvb_ca_en50221 en;
@@ -48,6 +50,7 @@ struct cxd {
 	int    mode;
 	int    ready;
 	int    dr;
+	int    write_busy;
 	int    slot_stat;
 
 	u8     amem[1024];
@@ -55,6 +58,9 @@ struct cxd {
 
 	int    cammode;
 	struct mutex lock;
+
+	u8     rbuf[1028];
+	u8     wbuf[1028];
 };
 
 static int i2c_write_reg(struct i2c_adapter *adapter, u8 adr,
@@ -73,7 +79,7 @@ static int i2c_write_reg(struct i2c_adapter *adapter, u8 adr,
 }
 
 static int i2c_write(struct i2c_adapter *adapter, u8 adr,
-		     u8 *data, u8 len)
+		     u8 *data, u16 len)
 {
 	struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = data, .len = len};
 
@@ -100,12 +106,12 @@ static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr,
 }
 
 static int i2c_read(struct i2c_adapter *adapter, u8 adr,
-		    u8 reg, u8 *data, u8 n)
+		    u8 reg, u8 *data, u16 n)
 {
 	struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
-				 .buf = &reg, .len = 1},
-				{.addr = adr, .flags = I2C_M_RD,
-				 .buf = data, .len = n} };
+				   .buf = &reg, .len = 1},
+				  {.addr = adr, .flags = I2C_M_RD,
+				   .buf = data, .len = n} };
 
 	if (i2c_transfer(adapter, msgs, 2) != 2) {
 		dev_err(&adapter->dev, "error in i2c_read\n");
@@ -114,14 +120,26 @@ static int i2c_read(struct i2c_adapter *adapter, u8 adr,
 	return 0;
 }
 
-static int read_block(struct cxd *ci, u8 adr, u8 *data, u8 n)
+static int read_block(struct cxd *ci, u8 adr, u8 *data, u16 n)
 {
-	int status;
+	int status = 0;
 
-	status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, adr);
+	if (ci->lastaddress != adr)
+		status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, adr);
 	if (!status) {
 		ci->lastaddress = adr;
-		status = i2c_read(ci->i2c, ci->cfg.adr, 1, data, n);
+
+		while (n) {
+			int len = n;
+
+			if (ci->cfg.max_i2c && (len > ci->cfg.max_i2c))
+				len = ci->cfg.max_i2c;
+			status = i2c_read(ci->i2c, ci->cfg.adr, 1, data, len);
+			if (status)
+				return status;
+			data += len;
+			n -= len;
+		}
 	}
 	return status;
 }
@@ -182,16 +200,16 @@ static int write_io(struct cxd *ci, u16 address, u8 val)
 
 static int write_regm(struct cxd *ci, u8 reg, u8 val, u8 mask)
 {
-	int status;
+	int status = 0;
 
-	status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, reg);
+	if (ci->lastaddress != reg)
+		status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, reg);
 	if (!status && reg >= 6 && reg <= 8 && mask != 0xff)
 		status = i2c_read_reg(ci->i2c, ci->cfg.adr, 1, &ci->regs[reg]);
+	ci->lastaddress = reg;
 	ci->regs[reg] = (ci->regs[reg] & (~mask)) | val;
-	if (!status) {
-		ci->lastaddress = reg;
+	if (!status)
 		status = i2c_write_reg(ci->i2c, ci->cfg.adr, 1, ci->regs[reg]);
-	}
 	if (reg == 0x20)
 		ci->regs[reg] &= 0x7f;
 	return status;
@@ -203,16 +221,31 @@ static int write_reg(struct cxd *ci, u8 reg, u8 val)
 }
 
 #ifdef BUFFER_MODE
-static int write_block(struct cxd *ci, u8 adr, u8 *data, int n)
+static int write_block(struct cxd *ci, u8 adr, u8 *data, u16 n)
 {
-	int status;
-	u8 buf[256] = {1};
-
-	status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, adr);
-	if (!status) {
-		ci->lastaddress = adr;
-		memcpy(buf + 1, data, n);
-		status = i2c_write(ci->i2c, ci->cfg.adr, buf, n + 1);
+	int status = 0;
+	u8 *buf = ci->wbuf;
+
+	if (ci->lastaddress != adr)
+		status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, adr);
+	if (status)
+		return status;
+	dev_info(&ci->i2c->dev, "write_block %d\n", n);
+
+	ci->lastaddress = adr;
+	buf[0] = 1;
+	while (n) {
+		int len = n;
+
+		if (ci->cfg.max_i2c && (len + 1 > ci->cfg.max_i2c))
+			len = ci->cfg.max_i2c - 1;
+		dev_info(&ci->i2c->dev, "write %d\n", len);
+		memcpy(buf + 1, data, len);
+		status = i2c_write(ci->i2c, ci->cfg.adr, buf, len + 1);
+		if (status)
+			return status;
+		n -= len;
+		data += len;
 	}
 	return status;
 }
@@ -238,6 +271,8 @@ static void set_mode(struct cxd *ci, int mode)
 
 static void cam_mode(struct cxd *ci, int mode)
 {
+	u8 dummy;
+
 	if (mode == ci->cammode)
 		return;
 
@@ -246,16 +281,15 @@ static void cam_mode(struct cxd *ci, int mode)
 		write_regm(ci, 0x20, 0x80, 0x80);
 		break;
 	case 0x01:
-#ifdef BUFFER_MODE
 		if (!ci->en.read_data)
 			return;
+		ci->write_busy = 0;
 		dev_info(&ci->i2c->dev, "enable cam buffer mode\n");
-		/* write_reg(ci, 0x0d, 0x00); */
-		/* write_reg(ci, 0x0e, 0x01); */
+		write_reg(ci, 0x0d, 0x00);
+		write_reg(ci, 0x0e, 0x01);
 		write_regm(ci, 0x08, 0x40, 0x40);
-		/* read_reg(ci, 0x12, &dummy); */
+		read_reg(ci, 0x12, &dummy);
 		write_regm(ci, 0x08, 0x80, 0x80);
-#endif
 		break;
 	default:
 		break;
@@ -325,7 +359,10 @@ static int init(struct cxd *ci)
 		if (status < 0)
 			break;
 
-		if (ci->cfg.clock_mode) {
+		if (ci->cfg.clock_mode == 2) {
+			/* bitrate*2^13/ 72000 */
+			u32 reg = ((ci->cfg.bitrate << 13) + 71999) / 72000;
+
 			if (ci->cfg.polarity) {
 				status = write_reg(ci, 0x09, 0x6f);
 				if (status < 0)
@@ -335,6 +372,25 @@ static int init(struct cxd *ci)
 				if (status < 0)
 					break;
 			}
+			status = write_reg(ci, 0x20, 0x08);
+			if (status < 0)
+				break;
+			status = write_reg(ci, 0x21, (reg >> 8) & 0xff);
+			if (status < 0)
+				break;
+			status = write_reg(ci, 0x22, reg & 0xff);
+			if (status < 0)
+				break;
+		} else if (ci->cfg.clock_mode == 1) {
+			if (ci->cfg.polarity) {
+				status = write_reg(ci, 0x09, 0x6f); /* D */
+				if (status < 0)
+					break;
+			} else {
+				status = write_reg(ci, 0x09, 0x6d);
+				if (status < 0)
+					break;
+			}
 			status = write_reg(ci, 0x20, 0x68);
 			if (status < 0)
 				break;
@@ -346,7 +402,7 @@ static int init(struct cxd *ci)
 				break;
 		} else {
 			if (ci->cfg.polarity) {
-				status = write_reg(ci, 0x09, 0x4f);
+				status = write_reg(ci, 0x09, 0x4f); /* C */
 				if (status < 0)
 					break;
 			} else {
@@ -354,7 +410,6 @@ static int init(struct cxd *ci)
 				if (status < 0)
 					break;
 			}
-
 			status = write_reg(ci, 0x20, 0x28);
 			if (status < 0)
 				break;
@@ -401,7 +456,6 @@ static int read_attribute_mem(struct dvb_ca_en50221 *ca,
 	set_mode(ci, 1);
 	read_pccard(ci, address, &val, 1);
 	mutex_unlock(&ci->lock);
-	/* printk(KERN_INFO "%02x:%02x\n", address,val); */
 	return val;
 }
 
@@ -446,6 +500,9 @@ static int slot_reset(struct dvb_ca_en50221 *ca, int slot)
 {
 	struct cxd *ci = ca->data;
 
+	if (ci->cammode)
+		read_data(ca, slot, ci->rbuf, 0);
+
 	mutex_lock(&ci->lock);
 	cam_mode(ci, 0);
 	write_reg(ci, 0x00, 0x21);
@@ -465,7 +522,6 @@ static int slot_reset(struct dvb_ca_en50221 *ca, int slot)
 		}
 	}
 	mutex_unlock(&ci->lock);
-	/* msleep(500); */
 	return 0;
 }
 
@@ -474,11 +530,19 @@ static int slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
 	struct cxd *ci = ca->data;
 
 	dev_info(&ci->i2c->dev, "%s\n", __func__);
+	if (ci->cammode)
+		read_data(ca, slot, ci->rbuf, 0);
 	mutex_lock(&ci->lock);
+	write_reg(ci, 0x00, 0x21);
+	write_reg(ci, 0x06, 0x1F);
+	msleep(300);
+
 	write_regm(ci, 0x09, 0x08, 0x08);
 	write_regm(ci, 0x20, 0x80, 0x80); /* Reset CAM Mode */
 	write_regm(ci, 0x06, 0x07, 0x07); /* Clear IO Mode */
+
 	ci->mode = -1;
+	ci->write_busy = 0;
 	mutex_unlock(&ci->lock);
 	return 0;
 }
@@ -490,9 +554,7 @@ static int slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
 	mutex_lock(&ci->lock);
 	write_regm(ci, 0x09, 0x00, 0x08);
 	set_mode(ci, 0);
-#ifdef BUFFER_MODE
 	cam_mode(ci, 1);
-#endif
 	mutex_unlock(&ci->lock);
 	return 0;
 }
@@ -510,8 +572,10 @@ static int campoll(struct cxd *ci)
 		ci->dr = 1;
 		dev_info(&ci->i2c->dev, "DR\n");
 	}
-	if (istat & 0x20)
+	if (istat & 0x20) {
+		ci->write_busy = 0;
 		dev_info(&ci->i2c->dev, "WC\n");
+	}
 
 	if (istat & 2) {
 		u8 slotstat;
@@ -519,7 +583,8 @@ static int campoll(struct cxd *ci)
 		read_reg(ci, 0x01, &slotstat);
 		if (!(2 & slotstat)) {
 			if (!ci->slot_stat) {
-				ci->slot_stat = DVB_CA_EN50221_POLL_CAM_PRESENT;
+				ci->slot_stat |=
+					      DVB_CA_EN50221_POLL_CAM_PRESENT;
 				write_regm(ci, 0x03, 0x08, 0x08);
 			}
 
@@ -531,8 +596,8 @@ static int campoll(struct cxd *ci)
 				ci->ready = 0;
 			}
 		}
-		if (istat & 8 &&
-		    ci->slot_stat == DVB_CA_EN50221_POLL_CAM_PRESENT) {
+		if ((istat & 8) &&
+		    (ci->slot_stat == DVB_CA_EN50221_POLL_CAM_PRESENT)) {
 			ci->ready = 1;
 			ci->slot_stat |= DVB_CA_EN50221_POLL_CAM_READY;
 		}
@@ -553,7 +618,6 @@ static int poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
 	return ci->slot_stat;
 }
 
-#ifdef BUFFER_MODE
 static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount)
 {
 	struct cxd *ci = ca->data;
@@ -571,23 +635,33 @@ static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount)
 	mutex_lock(&ci->lock);
 	read_reg(ci, 0x0f, &msb);
 	read_reg(ci, 0x10, &lsb);
-	len = (msb << 8) | lsb;
+	len = ((u16)msb << 8) | lsb;
+	if (len > ecount || len < 2) {
+		/* read it anyway or cxd may hang */
+		read_block(ci, 0x12, ci->rbuf, len);
+		mutex_unlock(&ci->lock);
+		return -EIO;
+	}
 	read_block(ci, 0x12, ebuf, len);
 	ci->dr = 0;
 	mutex_unlock(&ci->lock);
-
 	return len;
 }
 
+#ifdef BUFFER_MODE
+
 static int write_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount)
 {
 	struct cxd *ci = ca->data;
 
+	if (ci->write_busy)
+		return -EAGAIN;
 	mutex_lock(&ci->lock);
 	dev_info(&ci->i2c->dev, "%s %d\n", __func__, ecount);
 	write_reg(ci, 0x0d, ecount >> 8);
 	write_reg(ci, 0x0e, ecount & 0xff);
 	write_block(ci, 0x11, ebuf, ecount);
+	ci->write_busy = 1;
 	mutex_unlock(&ci->lock);
 	return ecount;
 }
diff --git a/drivers/staging/media/cxd2099/cxd2099.h b/drivers/staging/media/cxd2099/cxd2099.h
index 0eb607c..f4b29b1 100644
--- a/drivers/staging/media/cxd2099/cxd2099.h
+++ b/drivers/staging/media/cxd2099/cxd2099.h
@@ -30,8 +30,10 @@
 struct cxd2099_cfg {
 	u32 bitrate;
 	u8  adr;
-	u8  polarity:1;
-	u8  clock_mode:1;
+	u8  polarity;
+	u8  clock_mode;
+
+	u32 max_i2c;
 };
 
 #if defined(CONFIG_DVB_CXD2099) || \
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 5/7] [staging] cxd2099/cxd2099.c: Removed useless printing in cxd2099 driver
  2017-06-25 21:37 [PATCH v2 0/7] Add block read/write to en50221 CAM functions Jasmin J.
                   ` (3 preceding siblings ...)
  2017-06-25 21:37 ` [PATCH v2 4/7] [staging] cxd2099/cxd2099.c/.h: Fixed buffer mode Jasmin J.
@ 2017-06-25 21:37 ` Jasmin J.
  2017-06-25 21:37 ` [PATCH v2 6/7] [staging] cxd2099/cxd2099.c: Removed printing in write_block Jasmin J.
  2017-06-25 21:37 ` [PATCH v2 7/7] [staging] cxd2099/cxd2099.c: Activate cxd2099 buffer mode Jasmin J.
  6 siblings, 0 replies; 8+ messages in thread
From: Jasmin J. @ 2017-06-25 21:37 UTC (permalink / raw)
  To: linux-media; +Cc: mchehab, max.kellermann, rjkm, d.scheller, jasmin

From: Ralph Metzler <rjkm@metzlerbros.de>

campoll and read_data are called very often and the printouts are very
annoying and make the driver unusable. They seem to be left over from
developing the buffer mode.

Original code change by Ralph Metzler, modified by Jasmin Jessich to
match current Kernel code.

Signed-off-by: Ralph Metzler <rjkm@metzlerbros.de>
Signed-off-by: Jasmin Jessich <jasmin@anw.at>
---
 drivers/staging/media/cxd2099/cxd2099.c | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/drivers/staging/media/cxd2099/cxd2099.c b/drivers/staging/media/cxd2099/cxd2099.c
index 60d8dd0..6426ff1 100644
--- a/drivers/staging/media/cxd2099/cxd2099.c
+++ b/drivers/staging/media/cxd2099/cxd2099.c
@@ -568,14 +568,10 @@ static int campoll(struct cxd *ci)
 		return 0;
 	write_reg(ci, 0x05, istat);
 
-	if (istat & 0x40) {
+	if (istat & 0x40)
 		ci->dr = 1;
-		dev_info(&ci->i2c->dev, "DR\n");
-	}
-	if (istat & 0x20) {
+	if (istat & 0x20)
 		ci->write_busy = 0;
-		dev_info(&ci->i2c->dev, "WC\n");
-	}
 
 	if (istat & 2) {
 		u8 slotstat;
@@ -628,7 +624,6 @@ static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount)
 	campoll(ci);
 	mutex_unlock(&ci->lock);
 
-	dev_info(&ci->i2c->dev, "%s\n", __func__);
 	if (!ci->dr)
 		return 0;
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 6/7] [staging] cxd2099/cxd2099.c: Removed printing in write_block
  2017-06-25 21:37 [PATCH v2 0/7] Add block read/write to en50221 CAM functions Jasmin J.
                   ` (4 preceding siblings ...)
  2017-06-25 21:37 ` [PATCH v2 5/7] [staging] cxd2099/cxd2099.c: Removed useless printing in cxd2099 driver Jasmin J.
@ 2017-06-25 21:37 ` Jasmin J.
  2017-06-25 21:37 ` [PATCH v2 7/7] [staging] cxd2099/cxd2099.c: Activate cxd2099 buffer mode Jasmin J.
  6 siblings, 0 replies; 8+ messages in thread
From: Jasmin J. @ 2017-06-25 21:37 UTC (permalink / raw)
  To: linux-media; +Cc: mchehab, max.kellermann, rjkm, d.scheller, jasmin

From: Jasmin Jessich <jasmin@anw.at>

There were remaining debug prints which haven't been found earlier due to
the disabled buffer mode (see commit "Removed useless printing in cxd2099
driver" for the already removed printings.

Signed-off-by: Jasmin Jessich <jasmin@anw.at>
---
 drivers/staging/media/cxd2099/cxd2099.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/staging/media/cxd2099/cxd2099.c b/drivers/staging/media/cxd2099/cxd2099.c
index 6426ff1..3431cf6 100644
--- a/drivers/staging/media/cxd2099/cxd2099.c
+++ b/drivers/staging/media/cxd2099/cxd2099.c
@@ -230,7 +230,6 @@ static int write_block(struct cxd *ci, u8 adr, u8 *data, u16 n)
 		status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, adr);
 	if (status)
 		return status;
-	dev_info(&ci->i2c->dev, "write_block %d\n", n);
 
 	ci->lastaddress = adr;
 	buf[0] = 1;
@@ -239,7 +238,6 @@ static int write_block(struct cxd *ci, u8 adr, u8 *data, u16 n)
 
 		if (ci->cfg.max_i2c && (len + 1 > ci->cfg.max_i2c))
 			len = ci->cfg.max_i2c - 1;
-		dev_info(&ci->i2c->dev, "write %d\n", len);
 		memcpy(buf + 1, data, len);
 		status = i2c_write(ci->i2c, ci->cfg.adr, buf, len + 1);
 		if (status)
@@ -652,7 +650,6 @@ static int write_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount)
 	if (ci->write_busy)
 		return -EAGAIN;
 	mutex_lock(&ci->lock);
-	dev_info(&ci->i2c->dev, "%s %d\n", __func__, ecount);
 	write_reg(ci, 0x0d, ecount >> 8);
 	write_reg(ci, 0x0e, ecount & 0xff);
 	write_block(ci, 0x11, ebuf, ecount);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 7/7] [staging] cxd2099/cxd2099.c: Activate cxd2099 buffer mode
  2017-06-25 21:37 [PATCH v2 0/7] Add block read/write to en50221 CAM functions Jasmin J.
                   ` (5 preceding siblings ...)
  2017-06-25 21:37 ` [PATCH v2 6/7] [staging] cxd2099/cxd2099.c: Removed printing in write_block Jasmin J.
@ 2017-06-25 21:37 ` Jasmin J.
  6 siblings, 0 replies; 8+ messages in thread
From: Jasmin J. @ 2017-06-25 21:37 UTC (permalink / raw)
  To: linux-media; +Cc: mchehab, max.kellermann, rjkm, d.scheller, jasmin

From: Jasmin Jessich <jasmin@anw.at>

Activate the cxd2099 buffer mode.

Signed-off-by: Jasmin Jessich <jasmin@anw.at>
---
 drivers/staging/media/cxd2099/cxd2099.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/staging/media/cxd2099/cxd2099.c b/drivers/staging/media/cxd2099/cxd2099.c
index 3431cf6..f28916e 100644
--- a/drivers/staging/media/cxd2099/cxd2099.c
+++ b/drivers/staging/media/cxd2099/cxd2099.c
@@ -33,7 +33,8 @@
 
 #include "cxd2099.h"
 
-/* #define BUFFER_MODE 1 */
+/* comment this line to deactivate the cxd2099ar buffer mode */
+#define BUFFER_MODE 1
 
 static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount);
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2017-06-25 21:37 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-06-25 21:37 [PATCH v2 0/7] Add block read/write to en50221 CAM functions Jasmin J.
2017-06-25 21:37 ` [PATCH v2 1/7] [media] dvb-core/dvb_ca_en50221.c: State UNINITIALISED instead of INVALID Jasmin J.
2017-06-25 21:37 ` [PATCH v2 2/7] [media] dvb-core/dvb_ca_en50221.c: Increase timeout for link init Jasmin J.
2017-06-25 21:37 ` [PATCH v2 3/7] [media] dvb-core/dvb_ca_en50221.c: Add block read/write functions Jasmin J.
2017-06-25 21:37 ` [PATCH v2 4/7] [staging] cxd2099/cxd2099.c/.h: Fixed buffer mode Jasmin J.
2017-06-25 21:37 ` [PATCH v2 5/7] [staging] cxd2099/cxd2099.c: Removed useless printing in cxd2099 driver Jasmin J.
2017-06-25 21:37 ` [PATCH v2 6/7] [staging] cxd2099/cxd2099.c: Removed printing in write_block Jasmin J.
2017-06-25 21:37 ` [PATCH v2 7/7] [staging] cxd2099/cxd2099.c: Activate cxd2099 buffer mode Jasmin J.

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.