Mailing List archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[linux-dvb] Re: Nova-s CAM/CI support
On Wednesday 12 May 2004 23:31, you wrote:
> On Wednesday 12 May 2004 20:11, you wrote:
> > I have tested the cam_* utils that were mentioned on the list recently,
> > and it seems that my problems with the CAM getting reset is not caused
> > by MythTV itself, but perhaps by either libdvbci (which I assume MythTV
> > uses) or the budget-ci driver?
> >
> > After running cam_test for a while I get "ERROR: CAM: Read failed: slot
> > 0, tcid 1". The error seems to occur pretty randomly (after half a
> > minute, a couple of minutes or even after an hour or so).
> >
> > The actual error message is printed from line 407 in libdvbci/ci.cc:
> > $ nl libdvb-0.5.4/libdvbci/ci.cc | grep "Read failed"
> > 407 esyslog("ERROR: CAM: Read failed: slot %d, tcid %d\n",
> > slot, tcid);
> >
> > I'd appreciate it if someone a bit more knowledgeable could take a look
> > at the logs below and tell me what's going on. I don't know how this
> > stuff works but to me it looks like there are two interrupts at the same
> > time, and somehow the driver thread gets confused by this?
>
> Hi, if you have a moment, can you give the attached patch a go? I've
> hopefully sorted out the locking....
Oops - found a slight locking bug, sorry.
Index: linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
===================================================================
RCS file: /cvs/linuxtv/dvb-kernel/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.c,v
retrieving revision 1.9
diff -a -u -b -r1.9 dvb_ca_en50221.c
--- linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.c 3 May 2004 16:29:27 -0000 1.9
+++ linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.c 12 May 2004 22:38:11 -0000
@@ -34,7 +34,7 @@
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
-#include <asm/semaphore.h>
+#include <asm/rwsem.h>
#include <asm/atomic.h>
#include "dvb_ca_en50221.h"
@@ -108,7 +108,7 @@
int link_buf_size;
/* semaphore for syncing access to slot structure */
- struct semaphore sem;
+ struct rw_semaphore sem;
/* buffer for incoming packets */
struct dvb_ringbuffer rx_buffer;
@@ -199,7 +199,6 @@
static int dvb_ca_en50221_check_camstatus(struct dvb_ca_private* ca, int slot)
{
int slot_status;
- int status;
int cam_present_now;
int cam_changed;
@@ -209,9 +208,7 @@
}
/* poll mode */
- if ((status = down_interruptible(&ca->slot_info[slot].sem)) != 0) return status;
slot_status = ca->pub->poll_slot_status(ca->pub, slot);
- up(&ca->slot_info[slot].sem);
cam_present_now = (slot_status & DVB_CA_EN50221_POLL_CAM_PRESENT) ? 1: 0;
cam_changed = (slot_status & DVB_CA_EN50221_POLL_CAM_CHANGED) ? 1: 0;
@@ -550,11 +547,9 @@
dprintk ("%s\n", __FUNCTION__);
- /* acquire the slot */
- if ((status = down_interruptible(&ca->slot_info[slot].sem)) != 0) return status;
-
/* check if we have space for a link buf in the rx_buffer */
if (ebuf == NULL) {
+ down_read(&ca->slot_info[slot].sem);
if (dvb_ringbuffer_free(&ca->slot_info[slot].rx_buffer) <
(ca->slot_info[slot].link_buf_size + DVB_RINGBUFFER_PKTHDRSIZE)) {
status = -EAGAIN;
@@ -564,11 +559,6 @@
/* reset the interface if there's been a tx error */
if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) goto exit;
- if (status & STATUSREG_TXERR) {
- ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
- status = -EIO;
- goto exit;
- }
if (!(status & STATUSREG_DA)) {
/* no data */
status = 0;
@@ -630,11 +620,10 @@
if ((buf[1] & 0x80) == 0x00) {
wake_up_interruptible(&ca->wait_queue);
}
-
status = bytes_read;
exit:
- up(&ca->slot_info[slot].sem);
+ if (ebuf == NULL) up_read(&ca->slot_info[slot].sem);
return status;
}
@@ -662,16 +651,8 @@
// sanity check
if (bytes_write > ca->slot_info[slot].link_buf_size) return -EINVAL;
- /* acquire the slot */
- if ((status = down_interruptible(&ca->slot_info[slot].sem)) != 0) return status;
-
/* reset the interface if there's been a tx error */
if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) goto exitnowrite;
- if (status & STATUSREG_TXERR) {
- ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
- status = -EIO;
- goto exitnowrite;
- }
/* check if interface is actually waiting for us to read from it */
if (status & STATUSREG_DA) {
@@ -711,7 +692,6 @@
ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN);
exitnowrite:
- up(&ca->slot_info[slot].sem);
return status;
}
@@ -729,16 +709,14 @@
*/
static int dvb_ca_en50221_slot_shutdown(struct dvb_ca_private* ca, int slot)
{
- int status;
-
dprintk ("%s\n", __FUNCTION__);
- if ((status = down_interruptible(&ca->slot_info[slot].sem)) != 0) return status;
ca->pub->slot_shutdown(ca->pub, slot);
ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
+ down_write(&ca->slot_info[slot].sem);
if (ca->slot_info[slot].rx_buffer.data) vfree(ca->slot_info[slot].rx_buffer.data);
ca->slot_info[slot].rx_buffer.data = NULL;
- up(&ca->slot_info[slot].sem);
+ up_write(&ca->slot_info[slot].sem);
/* need to wake up all processes to check if they're now
trying to write to a defunct CAM */
@@ -1266,7 +1244,7 @@
while((slot_count < ca->slot_count) && (!found)) {
if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) goto nextslot;
- if ((*result = down_interruptible(&ca->slot_info[slot].sem)) != 0) return 1;
+ down_read(&ca->slot_info[slot].sem);
idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen);
while(idx != -1) {
@@ -1281,7 +1259,7 @@
idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen);
}
- if (!found) up(&ca->slot_info[slot].sem);
+ if (!found) up_read(&ca->slot_info[slot].sem);
nextslot:
slot = (slot + 1) % ca->slot_count;
@@ -1378,7 +1356,7 @@
status = pktlen;
exit:
- up(&ca->slot_info[slot].sem);
+ up_read(&ca->slot_info[slot].sem);
return status;
}
@@ -1406,7 +1384,9 @@
for(i=0; i< ca->slot_count; i++) {
if (ca->slot_info[i].slot_state == DVB_CA_SLOTSTATE_RUNNING) {
+ down_write(&ca->slot_info[i].sem);
dvb_ringbuffer_flush(&ca->slot_info[i].rx_buffer);
+ up_write(&ca->slot_info[i].sem);
}
}
@@ -1464,7 +1444,7 @@
dprintk ("%s\n", __FUNCTION__);
if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) {
- up(&ca->slot_info[slot].sem);
+ up_read(&ca->slot_info[slot].sem);
mask |= POLLIN;
}
@@ -1475,7 +1455,7 @@
poll_wait(file, &ca->wait_queue, wait);
if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) {
- up(&ca->slot_info[slot].sem);
+ up_read(&ca->slot_info[slot].sem);
mask |= POLLIN;
}
@@ -1559,7 +1539,7 @@
ca->slot_info[i].slot_state = DVB_CA_SLOTSTATE_NONE;
atomic_set(&ca->slot_info[i].camchange_count, 0);
ca->slot_info[i].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED;
- init_MUTEX(&ca->slot_info[i].sem);
+ init_rwsem(&ca->slot_info[i].sem);
}
if (signal_pending(current)) {
Index: linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.h
===================================================================
RCS file: /cvs/linuxtv/dvb-kernel/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.h,v
retrieving revision 1.1
diff -a -u -b -r1.1 dvb_ca_en50221.h
--- linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.h 5 Apr 2004 12:17:33 -0000 1.1
+++ linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.h 12 May 2004 22:38:11 -0000
@@ -42,6 +42,9 @@
/* Structure describing a CA interface */
struct dvb_ca_en50221 {
+ /* NOTE: the read_*, write_* and poll_slot_status functions must use locks as
+ * they may be called from several threads at once */
+
/* functions for accessing attribute memory on the CAM */
int (*read_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address);
int (*write_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address, u8 value);
Home |
Main Index |
Thread Index