summaryrefslogtreecommitdiff
path: root/linux
diff options
context:
space:
mode:
Diffstat (limited to 'linux')
-rw-r--r--linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.c88
1 files changed, 56 insertions, 32 deletions
diff --git a/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
index 02f40f5e0..496caeb05 100644
--- a/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
+++ b/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
@@ -156,6 +156,9 @@ struct dvb_ca_private {
/* Flag indicating the thread should wake up now */
int wakeup:1;
+ /* One of the slots in this interface does not support IRQs */
+ int needpolling:1;
+
/* Delay the main thread should use */
unsigned long delay;
@@ -562,7 +565,7 @@ static int dvb_ca_en50221_read_data(struct dvb_ca_private* ca, int slot, u8* ebu
/* acquire the slot */
if ((status = down_interruptible(&ca->slot_info[slot].sem)) != 0) return status;
- /* check if we have space for at a link buf in the rx_buffer */
+ /* check if we have space for a link buf in the rx_buffer */
if (ebuf == NULL) {
if (dvb_ringbuffer_free(&ca->slot_info[slot].rx_buffer) <
(ca->slot_info[slot].link_buf_size + DVB_RINGBUFFER_PKTHDRSIZE)) {
@@ -634,6 +637,12 @@ static int dvb_ca_en50221_read_data(struct dvb_ca_private* ca, int slot, u8* ebu
} else {
memcpy(ebuf, buf, bytes_read);
}
+
+ /* wake up readers when a last_fragment is received */
+ if ((buf[1] & 0x80) == 0x00) {
+ wake_up_interruptible(&ca->wait_queue);
+ }
+
status = bytes_read;
exit:
@@ -669,7 +678,7 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private* ca, int slot, u8* bu
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 exit;
+ 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;
@@ -715,7 +724,6 @@ exit:
exitnowrite:
up(&ca->slot_info[slot].sem);
- if (bytes_write >= 0) wake_up_interruptible(&ca->wait_queue);
return status;
}
@@ -744,7 +752,7 @@ static int dvb_ca_en50221_slot_shutdown(struct dvb_ca_private* ca, int slot)
ca->slot_info[slot].rx_buffer.data = NULL;
up(&ca->slot_info[slot].sem);
- /* need to wake up all write processes to check if they're now
+ /* need to wake up all processes to check if they're now
trying to write to a defunct CAM */
wake_up_interruptible(&ca->wait_queue);
@@ -835,6 +843,7 @@ void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221* pubca, int slot)
dvb_ca_en50221_thread_wakeup(ca);
}
if (flags & STATUSREG_FR) {
+ // FIXME: is this right?
wake_up_interruptible(&ca->wait_queue);
}
break;
@@ -866,13 +875,18 @@ static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private* ca)
*
* @param ca CA instance.
*/
-static int dvb_ca_en50221_thread_should_wakeup(struct dvb_ca_private* ca)
+static int dvb_ca_en50221_thread_should_wakeup(struct dvb_ca_private* ca, int* iterations)
{
if (ca->wakeup) {
ca->wakeup = 0;
return 1;
}
if (ca->exit) return 1;
+ if (ca->needpolling) {
+ if (*iterations) return 1;
+ (*iterations)++;
+ }
+
return 0;
}
@@ -888,35 +902,42 @@ static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private* ca)
int curdelay = 100000000;
int slot;
+ ca->needpolling = 0;
for(slot=0; slot < ca->slot_count; slot++) {
- if (!ca->open) {
+ switch(ca->slot_info[slot].slot_state) {
+ default:
+ case DVB_CA_SLOTSTATE_NONE:
+ case DVB_CA_SLOTSTATE_INVALID:
delay = HZ*60;
- if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) delay = HZ/10;
- } else {
+ if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) {
+ ca->needpolling = 1;
+ delay = HZ/10;
+ }
+ break;
- switch(ca->slot_info[slot].slot_state) {
- default:
- case DVB_CA_SLOTSTATE_NONE:
- case DVB_CA_SLOTSTATE_INVALID:
- delay = HZ*60;
- if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) delay = HZ/10;
- break;
+ case DVB_CA_SLOTSTATE_UNINITIALISED:
+ case DVB_CA_SLOTSTATE_WAITREADY:
+ case DVB_CA_SLOTSTATE_VALIDATE:
+ case DVB_CA_SLOTSTATE_WAITFR:
+ case DVB_CA_SLOTSTATE_LINKINIT:
+ ca->needpolling = 1;
+ delay = HZ/10;
+ break;
- case DVB_CA_SLOTSTATE_UNINITIALISED:
- case DVB_CA_SLOTSTATE_WAITREADY:
- case DVB_CA_SLOTSTATE_VALIDATE:
- case DVB_CA_SLOTSTATE_WAITFR:
- case DVB_CA_SLOTSTATE_LINKINIT:
+ case DVB_CA_SLOTSTATE_RUNNING:
+ delay = HZ*60;
+ if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) {
+ ca->needpolling = 1;
delay = HZ/10;
- break;
-
- case DVB_CA_SLOTSTATE_RUNNING:
- delay = HZ*60;
- if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) delay = HZ/10;
+ }
+ if (ca->open) {
if ((!ca->slot_info[slot].da_irq_supported) ||
- (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_DA))) delay = HZ/100;
- break;
+ (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_DA))) {
+ ca->needpolling = 1;
+ delay = HZ/100;
+ }
}
+ break;
}
if (delay < curdelay) curdelay = delay;
@@ -938,6 +959,7 @@ static int dvb_ca_en50221_thread(void* data)
int flags;
int pktcount;
void* rxbuf;
+ int iterations;
dprintk ("%s\n", __FUNCTION__);
@@ -952,7 +974,8 @@ static int dvb_ca_en50221_thread(void* data)
while(!ca->exit) {
/* sleep for a bit */
if (!ca->wakeup) {
- flags = wait_event_interruptible_timeout(ca->thread_queue, dvb_ca_en50221_thread_should_wakeup(ca), ca->delay);
+ iterations = 0;
+ flags = wait_event_interruptible_timeout(ca->thread_queue, dvb_ca_en50221_thread_should_wakeup(ca, &iterations), ca->delay);
if ((flags == -ERESTARTSYS) || ca->exit) {
/* got signal or quitting */
break;
@@ -1224,6 +1247,7 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file, const char *buf, size_
fragbuf[1] = ((fragpos + fraglen) < count) ? 0x80 : 0x00;
if ((status = copy_from_user(fragbuf+2, buf+fragpos, fraglen)) != 0) goto exit;
+ // FIXME: can this loop be improved?
while(1) {
status = dvb_ca_en50221_write_data(ca, slot, fragbuf, fraglen+2);
if (status == (fraglen+2)) break;
@@ -1234,10 +1258,9 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file, const char *buf, size_
fragpos += fraglen;
}
- status = count;
+ status = count + 2;
exit:
- dvb_ca_en50221_thread_wakeup(ca);
return status;
}
@@ -1365,8 +1388,9 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char *buf, size_t count
dispose = 0;
} while (!last_fragment);
- if ((status = copy_to_user(buf, &slot, 1)) != 0) goto exit;
- if ((status = copy_to_user(buf+1, &connection_id, 1)) != 0) goto exit;
+ hdr[0] = slot;
+ hdr[1] = connection_id;
+ if ((status = copy_to_user(buf, hdr, 2)) != 0) goto exit;
status = pktlen;
exit: