diff options
Diffstat (limited to 'linux')
-rw-r--r-- | linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.c | 88 |
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: |