--- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c 2008-07-13 23:51:29.000000000 +0200 +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c 2008-08-22 09:05:31.000000000 +0200 @@ -93,6 +93,9 @@ struct dvb_ca_slot { /* current state of the CAM */ int slot_state; + /* slot mutex for serializing data read/write access */ + struct mutex slotlock; + /* Number of CAMCHANGES that have occurred since last processing */ atomic_t camchange_count; @@ -589,6 +592,8 @@ static int dvb_ca_en50221_read_data(stru dprintk("%s\n", __func__); + mutex_lock(&ca->slot_info[slot].slotlock); + /* check if we have space for a link buf in the rx_buffer */ if (ebuf == NULL) { int buf_free; @@ -687,6 +692,7 @@ static int dvb_ca_en50221_read_data(stru status = bytes_read; exit: + mutex_unlock(&ca->slot_info[slot].slotlock); return status; } @@ -710,15 +716,22 @@ static int dvb_ca_en50221_write_data(str dprintk("%s\n", __func__); + mutex_lock(&ca->slot_info[slot].slotlock); - // sanity check + /* 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 */ + /* 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 + process the data if necessary. */ if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) goto exitnowrite; if (status & (STATUSREG_DA | STATUSREG_RE)) { + if (status & STATUSREG_DA) + dvb_ca_en50221_thread_wakeup(ca); + status = -EAGAIN; goto exitnowrite; } @@ -767,6 +780,7 @@ exit: ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN); exitnowrite: + mutex_unlock(&ca->slot_info[slot].slotlock); return status; } EXPORT_SYMBOL(dvb_ca_en50221_camchange_irq); @@ -1662,6 +1676,7 @@ int dvb_ca_en50221_init(struct dvb_adapt for (i = 0; i < slot_count; i++) { memset(&ca->slot_info[i], 0, sizeof(struct dvb_ca_slot)); ca->slot_info[i].slot_state = DVB_CA_SLOTSTATE_NONE; + mutex_init(&ca->slot_info[i].slotlock); atomic_set(&ca->slot_info[i].camchange_count, 0); ca->slot_info[i].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED; }