[mythtv-users] mythtv/pvr 250: why does it sometimes stop
recording?
Jens Axboe
mythtv-users at kernel.dk
Thu Oct 23 17:45:13 EDT 2003
On Thu, Oct 23 2003, marduk wrote:
> Thanks for the patch (you guys are cool). I'll give it a try tonite.
Probably want this one instead, the one attached was an earlier one.
This one closes more holes :)
diff -ur ivtv.vanilla/driver/ivtv-api.c ivtv/driver/ivtv-api.c
--- ivtv.vanilla/driver/ivtv-api.c 2003-10-03 07:02:34.000000000 +0200
+++ ivtv/driver/ivtv-api.c 2003-10-23 16:08:24.000000000 +0200
@@ -1175,7 +1175,7 @@
&result, 2, &data[0]);
if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "init error 20. Code %d\n",x);
- if (itv->capturing == 0) {
+ if (atomic_read(&itv->capturing) == 0) {
itv->trans_id = 0;
itv->first_read = 1;
@@ -1225,7 +1225,7 @@
&result, 2, &data[0]);
if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "startcap error 1. Code %d\n",x);
- if (itv->capturing == 0) {
+ if (atomic_read(&itv->capturing) == 0) {
/*Clear the following Interrupt mask bits: 0xd8000000 */
itv->irqmask = (itv->irqmask & ~IVTV_IRQ_MASK_CAPTURE);
writel(itv->irqmask,(itv->reg_mem + IVTV_REG_IRQMASK));
@@ -1233,7 +1233,7 @@
}
/*you're live! sit back and await interrupts :)*/
- itv->capturing++;
+ atomic_inc(&itv->capturing);
up(&itv->enc_sem_adm);
return 0;
}
@@ -1283,7 +1283,7 @@
IVTV_DEBUG(IVTV_DEBUG_INFO, "Decoder dmaq size %d\n",
itv->v4l2.streams[id->type].dma_q.elements);
- if (itv->decoding == 0)
+ if (atomic_read(&itv->decoding) == 0)
{
/* Clear pending interrupts */
IVTV_DEBUG(IVTV_DEBUG_INFO, "Clearing Interrupts\n");
@@ -1355,7 +1356,7 @@
&result, 2, &data[0]);
if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "COULDN'T START PLAYBACK %d\n",x);
- if (itv->decoding == 0)
+ if (atomic_read(&itv->decoding) == 0)
{
/*Clear the following Interrupt mask bits: 0xd8000000 */
itv->irqmask = (itv->irqmask & ~IVTV_IRQ_MASK_DECODE);
@@ -1364,7 +1365,7 @@
}
/*you're live! sit back and await interrupts :)*/
- itv->decoding++;
+ atomic_inc(&itv->decoding);
/* FIXME wrong semaphore still */
up(&itv->dec_sem_adm);
@@ -1380,7 +1381,7 @@
IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 unregister\n");
- if (itv->capturing >= 0) ivtv_stop_all_captures(itv);
+ if (atomic_read(&itv->capturing) >= 0) ivtv_stop_all_captures(itv);
if (itv->v4l2.tuner.table.tuner) kfree(itv->v4l2.tuner.table.tuner);
for (x=0; x < itv->v4l2.streamcount; x++) {
/* Catch a possible kernel panic */
@@ -1467,15 +1468,15 @@
IVTV_DEBUG(IVTV_DEBUG_INFO,"v4l2 read\n");
+ if (down_interruptible(&id->itv->v4l2.v4l2_lock))
+ return -ERESTARTSYS;
+
//FIXME need to handle non-blocking io
//FIXME needs locking
//FIXME this can be collapsed into 1 var i think
if ((id->itv->v4l2.streams[id->type].capturing == 0) &&
(id->itv->v4l2.streams[id->type].id == -1)) {
- if (down_interruptible(&id->itv->v4l2.v4l2_lock))
- return -ERESTARTSYS;
-
id->itv->v4l2.streams[id->type].capturing = 1;
id->itv->v4l2.streams[id->type].id = id->open_id;
@@ -1488,9 +1489,14 @@
up(&id->itv->v4l2.v4l2_lock);
} else {
if (id->open_id != id->itv->v4l2.streams[id->type].id)
- return -EBUSY;
+ ret = -EBUSY;
}
+ up(&id->itv->v4l2.v4l2_lock);
+
+ if (ret)
+ return ret;
+
if (filp->f_flags & O_NONBLOCK) {
if(!(ivtv_stream_has_data(id)) )
return -EAGAIN;
@@ -1514,21 +1520,27 @@
return -EINVAL;
}
+ if (down_interruptible(&id->itv->v4l2.v4l2_lock))
+ return -ERESTARTSYS;
+
// Initialize Decoder
/* FIXME we'll need to make this its own stream type */
- /* FIXME semaphore? */
if(id->itv->v4l2.streams[id->type].capturing == 0) {
id->itv->v4l2.streams[id->type].capturing = 1;
id->itv->v4l2.streams[id->type].id = id->open_id;
ret = ivtv_start_v4l2_decode(id);
} else {
if (id->open_id != id->itv->v4l2.streams[id->type].id)
- return -EBUSY;
+ ret = -EBUSY;
}
+ up(&id->itv->v4l2.v4l2_lock);
+
+ if (ret)
+ return ret;
+
/* do all the work */
- ret = ivtv_write(id, buf, count);
- return ret;
+ return ivtv_write(id, buf, count);
}
int ivtv_v4l2_close(struct inode *inode, struct file *filp) {
@@ -1546,8 +1558,9 @@
if (down_interruptible(&id->itv->v4l2.v4l2_lock))
return -ERESTARTSYS;
- id->itv->v4l2.streams[id->type].capturing = 0;
- id->itv->v4l2.streams[id->type].id = -1;
+
+ id->itv->v4l2.streams[id->type].capturing = 0;
+ id->itv->v4l2.streams[id->type].id = -1;
up(&id->itv->v4l2.v4l2_lock);
}
diff -ur ivtv.vanilla/driver/ivtv-driver.c ivtv/driver/ivtv-driver.c
--- ivtv.vanilla/driver/ivtv-driver.c 2003-10-03 07:17:14.000000000 +0200
+++ ivtv/driver/ivtv-driver.c 2003-10-23 16:30:39.000000000 +0200
@@ -165,21 +165,30 @@
}
}
-/* Adds buffers to the tail, effectively making a queue */
-int ivtv_enq_buf(struct ivtv_buffer_list *queue, struct ivtv_buffer *buf) {
+int ivtv_get_free_elements(struct ivtv_buffer_list *queue)
+{
unsigned long flags;
+ int elements;
spin_lock_irqsave(&queue->lock, flags);
+ elements = queue->elements;
+ spin_unlock_irqrestore(&queue->lock, flags);
+
+ return elements;
+}
+
+/* Adds buffers to the tail, effectively making a queue */
+int ivtv_enq_buf(struct ivtv_buffer_list *queue, struct ivtv_buffer *buf) {
+ unsigned long flags;
if (buf == NULL) {
IVTV_DEBUG(IVTV_DEBUG_ERR,"EnQ NULL buffer!\n");
- spin_unlock_irqrestore(&queue->lock, flags);
return -EINVAL;
}
+ spin_lock_irqsave(&queue->lock, flags);
list_add_tail(&buf->list, &queue->list);
queue->elements++;
-
spin_unlock_irqrestore(&queue->lock, flags);
return 0;
@@ -209,16 +218,13 @@
}
/* removes buffer from the head */
-struct ivtv_buffer *ivtv_deq_buf(struct ivtv_buffer_list *queue) {
+struct ivtv_buffer *__ivtv_deq_buf(struct ivtv_buffer_list *queue) {
struct ivtv_buffer *buf;
- unsigned long flags;
- spin_lock_irqsave(&queue->lock, flags);
/* make sure list has something to DeQ */
if (list_empty(&queue->list)) {
IVTV_DEBUG(IVTV_DEBUG_INFO,"DeQ from empty list!\n");
queue->elements = 0;
- spin_unlock_irqrestore(&queue->lock, flags);
return NULL;
}
@@ -230,6 +236,15 @@
queue->elements--;
+ return buf;
+}
+
+struct ivtv_buffer *ivtv_deq_buf(struct ivtv_buffer_list *queue) {
+ struct ivtv_buffer *buf;
+ unsigned long flags;
+
+ spin_lock_irqsave(&queue->lock, flags);
+ buf = __ivtv_deq_buf(queue);
spin_unlock_irqrestore(&queue->lock, flags);
return buf;
@@ -260,6 +275,7 @@
int ivtv_free_queue(struct ivtv_buffer_list *queue) {
struct ivtv_buffer *item;
+ unsigned long flags;
struct ivtv *itv;
int x;
@@ -268,20 +284,22 @@
return -EINVAL;
}
+ spin_lock_irqsave(&queue->lock, flags);
+
/* FIXME ugly */
/* verify ivtv before continuing */
for (x = 0; x < ivtv_cards_active; x++) {
if (queue->vdev->priv == &ivtv_cards[x]) break;
if (x == (ivtv_cards_active - 1)) {
queue->elements = 0;
- return 0;
+ goto out;
}
}
itv=(struct ivtv *)queue->vdev->priv;
while (list_empty(&queue->list) == 0) {
- item = ivtv_deq_buf(queue);
+ item = __ivtv_deq_buf(queue);
/* FIXME no check to see if it's mapped or not */
pci_unmap_single(itv->dev, item->dma_handle,
IVTV_DMA_BUF_SIZE, PCI_DMA_TODEVICE);
@@ -294,7 +312,8 @@
}
queue->elements = 0;
-
+out:
+ spin_unlock_irqrestore(&queue->lock, flags);
return 0;
}
@@ -335,7 +354,8 @@
int ivtv_move_queue(struct ivtv_buffer_list *src, struct ivtv_buffer_list *dst) {
struct ivtv_buffer *buf;
- while ((buf = ivtv_deq_buf(src))) {
+
+ while ((buf = ivtv_deq_buf(src))) {
ivtv_enq_buf(dst, buf);
}
@@ -351,15 +371,16 @@
if ( (fd = open(fn, 0, 0)) == -1) {
printk(KERN_INFO "Unable to open '%s'.\n", fn);
- return -EINVAL;
+ l = -EINVAL;
+ goto out;
}
/* the 2 means SEEK_END */
l = lseek(fd, 0L, 2);
if (l <= 0 || l > IVTV_FIRM_IMAGE_SIZE) {
printk(KERN_INFO "Firmware image too large '%s'\n", fn);
- sys_close(fd);
- return -ENOMEM;
+ l = -ENOMEM;
+ goto out;
}
/* the 2 means SEEK_SET */
@@ -367,10 +388,10 @@
if (read(fd, mem, l) != l){
printk(KERN_INFO "Failed to read '%s'.\n", fn);
- sys_close(fd);
- return -ENOMEM;
+ l = -ENOMEM;
}
+out:
close(fd);
set_fs(fs);
@@ -410,7 +431,7 @@
IVTV_DEBUG(IVTV_DEBUG_INFO, "Stopping firmware\n");
- if (itv->capturing) {
+ if (atomic_read(&itv->capturing)) {
x = ivtv_stop_all_captures(itv);
if (x) IVTV_DEBUG(IVTV_DEBUG_ERR, "stop_fw error 1. Code %d\n",x);
}
@@ -430,7 +451,7 @@
IVTV_DEBUG(IVTV_DEBUG_INFO, "Sleeping for 10ms\n");
set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(.01*HZ);
+ schedule_timeout(HZ/100);
/*halt dec firmware */
if (IVTV_250_V2 != itv->card_type) {
@@ -868,6 +889,8 @@
int x;
id.itv = itv;
+ down(&itv->v4l2.v4l2_lock);
+
for (x = 0; x < itv->v4l2.streamcount;x++) {
if (itv->v4l2.streams[x].capturing==1) {
id.type=x;
@@ -875,6 +898,7 @@
}
}
+ up(&itv->v4l2.v4l2_lock);
return 0;
}
@@ -894,7 +918,7 @@
}
/* only run these if we're shutting down the last cap */
- if (itv->capturing == 0) {
+ if (atomic_read(&itv->capturing) == 0) {
/* event notification (off)*/
data[0] = 0; /*type: 0 = refresh */
data[1] = 0; /*on/off: 0 = off */
@@ -919,7 +943,7 @@
IVTV_DEBUG(IVTV_DEBUG_ERR, "dma still pending! stopping anyway.\n");
/* only run these if we're shutting down the last cap */
- if (itv->capturing == 0) {
+ if (atomic_read(&itv->capturing) == 0) {
/* wait 1s for EOS interrupt */
sleep_on_timeout(&itv->cap_w, 1*HZ);
@@ -950,7 +974,7 @@
wake_up(&itv->dec_thread_w);
/* only run these if we're shutting down the last cap */
- if (itv->decoding == 0) {
+ if (atomic_read(&itv->decoding) == 0) {
/* event notification (off)*/
data[0] = 0; /* Event: 0 = audio change between stereo and mono */
data[1] = 0; /* Enable/Disable: 0 = disabled, 1 = enabled */
@@ -976,36 +1000,19 @@
/* clean up queues */
/* move free_q to full_q to clean up partially-filled buffers */
- while (itv->v4l2.streams[id->type].free_q.elements > 0) {
- buf = ivtv_deq_buf(&itv->v4l2.streams[id->type].free_q);
- if (buf == NULL) {
- IVTV_DEBUG(IVTV_DEBUG_ERR,
- "NULL buffer in close_stream (b)\n");
- break;
- }
+ while ((buf = ivtv_deq_buf(&itv->v4l2.streams[id->type].free_q))) {
buf->buffer.bytesused=0;
buf->readpos=0;
ivtv_enq_buf(&itv->v4l2.streams[id->type].full_q, buf);
}
- while (itv->v4l2.streams[id->type].full_q.elements > 0) {
- buf = ivtv_deq_buf(&itv->v4l2.streams[id->type].full_q);
- if (buf == NULL) {
- IVTV_DEBUG(IVTV_DEBUG_ERR,
- "NULL buffer in close_stream (a)\n");
- break;
- }
+ while ((buf = ivtv_deq_buf(&itv->v4l2.streams[id->type].full_q))) {
buf->buffer.bytesused=0;
buf->readpos=0;
ivtv_enq_buf(&itv->v4l2.streams[id->type].free_q, buf);
}
- while (itv->v4l2.streams[id->type].dma_q.elements > 0) {
- buf = ivtv_deq_buf(&itv->v4l2.streams[id->type].dma_q);
- if (buf == NULL) {
- IVTV_DEBUG(IVTV_DEBUG_ERR,
- "NULL buffer in close_stream (b)\n");
- break;
- }
+
+ while ((buf = ivtv_deq_buf(&itv->v4l2.streams[id->type].dma_q))) {
buf->buffer.bytesused=0;
buf->readpos=0;
ivtv_enq_buf(&itv->v4l2.streams[id->type].free_q, buf);
@@ -1029,17 +1036,21 @@
/* FIXME mpg only :/ */
struct ivtv_v4l2_stream *stream=&itv->v4l2.streams[IVTV_DEC_STREAM_TYPE_MPG];
daemonize();
+ exit_files(current);
reparent_to_init();
strcpy(current->comm, "ivtv-dec");
IVTV_DEBUG(IVTV_DEBUG_INFO, "ivtv_dec_thread: pid = %d, itv = 0x%08x\n",
current->pid, (u32)itv);
+ /* notify initiator that we are up and running */
+ up(&itv->enc_sem_adm);
+
while (itv->dec_thread_running) {
IVTV_DEBUG(IVTV_DEBUG_INFO, "starting thread %d\n", current->pid);
- while (itv->decoding) {
+ while (atomic_read(&itv->decoding)) {
/* don't want it to get interrupted */
- sleep_on_timeout(&itv->dec_thread_w, 0.1*HZ);
+ sleep_on_timeout(&itv->dec_thread_w, HZ/10);
if (itv->dec_dma_reset == 0) {
if (stream->dma_pending == 1) {
IVTV_DEBUG(IVTV_DEBUG_ERR,"ivtv_dec_thread: "
@@ -1380,8 +1391,7 @@
break;
}
- /* FIXME might need locking (unlikely) */
- free = itv->v4l2.streams[type].free_q.elements;
+ free = ivtv_get_free_elements(&itv->v4l2.streams[type].free_q);
/* increment the sequence # */
itv->v4l2.streams[type].seq++;
@@ -1390,7 +1400,7 @@
if (free <= bufs_needed) {
IVTV_DEBUG(IVTV_DEBUG_ERR, "Not enough free buffers, stream %d\n",
type);
- IVTV_DEBUG(IVTV_DEBUG_INFO, "(fullq: %d, freeq: %d, dmaq: %d)\n",
+ printk(KERN_DEBUG "(fullq: %d, freeq: %d, dmaq: %d)\n",
itv->v4l2.streams[type].full_q.elements,
free,
itv->v4l2.streams[type].dma_q.elements);
@@ -1554,9 +1564,8 @@
itv->dec_mbox = NULL;
itv->io_mem = NULL;
itv->reg_mem = NULL;
- itv->busy = 0;
- itv->capturing = 0;
- itv->decoding = 0;
+ atomic_set(&itv->capturing, 0);
+ atomic_set(&itv->decoding, 0);
itv->dec_dma_pending = 0;
itv->user_dma_to_device_state = NULL;
@@ -1761,6 +1770,8 @@
itv->dec_thread_running = 1;
itv->dec_thread_pid = kernel_thread(ivtv_dec_thread, itv,
CLONE_FS | CLONE_FILES);
+ /* wait for thread to finish starting */
+ down(&itv->enc_sem_adm);
}
return 0;
@@ -1801,7 +1812,7 @@
writel(itv->irqmask, (itv->reg_mem + IVTV_REG_IRQMASK));
IVTV_DEBUG(IVTV_DEBUG_INFO, "Stopping thread\n");
- itv->decoding = 0;
+ atomic_set(&itv->decoding, 0);
itv->dec_thread_running = 0;
wake_up(&itv->dec_thread_w);
@@ -1956,15 +1967,10 @@
IVTV_DEBUG(IVTV_DEBUG_INFO, " Read stream.. \n");
- if(down_interruptible(&itv->enc_sem_adm)) return -ERESTARTSYS;
-
- if (0 == itv->capturing) {
- up(&itv->enc_sem_adm);
+ if (atomic_read(&itv->capturing) == 0) {
IVTV_DEBUG(IVTV_DEBUG_ERR,
"Stream not initialized before read(shouldn't happen)\n");
return -EIO;
- } else {
- up(&itv->enc_sem_adm);
}
sleepctr = 0;
@@ -1972,7 +1978,7 @@
/* FIXME find a way to gracefully exit capture */
/* FIXME need spinlock here*/
- while (st->full_q.elements == 0) {
+ while (ivtv_get_free_elements(&st->full_q) == 0) {
sleepctr++;
sleep_on_timeout(&st->waitq, IVTV_SLEEP_WAIT);
@@ -2055,14 +2061,9 @@
buf = ivtv_deq_buf(&st->full_q);
ivtv_enq_buf(&st->free_q, buf);
- if (st->full_q.elements != 0) {
+ buf = ivtv_deq_peek_head(&st->full_q);
+ if (buf) {
tid = buf->buffer.sequence;
- buf = ivtv_deq_peek_head(&st->full_q);
- if (buf == NULL) {
- IVTV_DEBUG(IVTV_DEBUG_ERR,
- "Error obtaining buffer(shouldnt happen)\n");
- break;
- }
if (buf->buffer.sequence != tid) {
/* end of frame! */
st->ubytes = 0;
@@ -2549,13 +2550,11 @@
}
int ivtv_stream_has_data(struct ivtv_open_id *id) {
- if(id->itv->v4l2.streams[id->type].full_q.elements != 0) return 1;
- return 0;
+ return ivtv_get_free_elements(&id->itv->v4l2.streams[id->type].full_q);
}
int ivtv_dec_stream_has_space(struct ivtv_open_id *id) {
- if(id->itv->v4l2.streams[id->type].free_q.elements != 0) return 1;
- return 0;
+ return ivtv_get_free_elements(&id->itv->v4l2.streams[id->type].free_q);
}
unsigned int ivtv_dec_poll(struct file *filp, poll_table *wait) {
@@ -2565,6 +2564,9 @@
/* add stream's waitq to the poll list */
poll_wait(filp, &id->itv->v4l2.streams[id->type].waitq, wait);
+ if (down_interruptible(&id->itv->v4l2.v4l2_lock))
+ return -ERESTARTSYS;
+
if(ivtv_dec_stream_has_space(id)) {
mask |= POLLIN | POLLRDNORM; /* readable */
}
@@ -2574,6 +2576,7 @@
mask = POLLERR;
}
+ up(&id->itv->v4l2.v4l2_lock);
return mask;
}
@@ -2584,6 +2587,9 @@
/* add stream's waitq to the poll list */
poll_wait(filp, &id->itv->v4l2.streams[id->type].waitq, wait);
+ if (down_interruptible(&id->itv->v4l2.v4l2_lock))
+ return -ERESTARTSYS;
+
if(ivtv_stream_has_data(id)) {
mask |= POLLIN | POLLRDNORM; /* readable */
}
@@ -2593,6 +2599,7 @@
mask = POLLERR;
}
+ up(&id->itv->v4l2.v4l2_lock);
return mask;
}
@@ -2651,40 +2658,21 @@
int ivtv_close(struct ivtv_open_id *id) {
struct ivtv *itv=id->itv;
- int capflag=0, decflag=0, x;
- down(&itv->enc_sem_adm);
- if (itv->capturing) {
- capflag =1;
- }
- up(&itv->enc_sem_adm);
-
- /* FIXME needs semaphore */
- if(itv->decoding) {
- decflag=1;
- }
- /* end sem */
- if(capflag) {
- if( (id->type != IVTV_DEC_STREAM_TYPE_MPG) &&
- (id->type != IVTV_DEC_STREAM_TYPE_YUV)) {
- down(&itv->enc_sem_adm);
- itv->capturing--;
- up(&itv->enc_sem_adm);
- x = ivtv_stop_capture(id);
- return x;
+ if( (id->type != IVTV_DEC_STREAM_TYPE_MPG) && (id->type != IVTV_DEC_STREAM_TYPE_YUV)) {
+ if (atomic_read(&itv->capturing)) {
+ atomic_dec(&itv->capturing);
+ return ivtv_stop_capture(id);
}
}
- if(decflag) {
- if( (id->type == IVTV_DEC_STREAM_TYPE_MPG) ||
- (id->type == IVTV_DEC_STREAM_TYPE_YUV)) {
- /* FIXME needs semaphore */
- itv->decoding--;
- /* end sem */
- x = ivtv_stop_decode(id);
- return x;
+ if( (id->type == IVTV_DEC_STREAM_TYPE_MPG) || (id->type == IVTV_DEC_STREAM_TYPE_YUV)) {
+ if (atomic_read(&itv->decoding)) {
+ atomic_dec(&itv->decoding);
+ return ivtv_stop_decode(id);
}
}
+
return 0;
}
diff -ur ivtv.vanilla/driver/ivtv.h ivtv/driver/ivtv.h
--- ivtv.vanilla/driver/ivtv.h 2003-10-03 09:07:33.000000000 +0200
+++ ivtv/driver/ivtv.h 2003-10-23 15:50:51.000000000 +0200
@@ -632,8 +632,8 @@
int num; /* invalidate during init! */
int first_read; /* used to clean up stream */
int first_write; /* don't schedule decodes until buffers full */
- int busy, capturing; /* FIXME obseleted by v4l2|consolidate into flags? */
- int decoding;
+ atomic_t capturing;
+ atomic_t decoding;
struct semaphore enc_sem_r, enc_sem_w, enc_sem_adm;
struct semaphore dec_sem_r, dec_sem_w, dec_sem_adm;
struct semaphore dec_sched_dma_sem;
--
Jens Axboe
More information about the mythtv-users
mailing list