All of lore.kernel.org
 help / color / mirror / Atom feed
From: Gerd Knorr <kraxel@bytesex.org>
To: Linus Torvalds <torvalds@transmeta.com>,
	Kernel List <linux-kernel@vger.kernel.org>,
	video4linux list <video4linux-list@redhat.com>
Subject: [patch] videobuf update
Date: Thu, 31 Oct 2002 17:12:34 +0100	[thread overview]
Message-ID: <20021031161234.GA17340@bytesex.org> (raw)

  Hi Linus,

This patch updates the for the video-buf.c module (helper module for
video buffer management).  Some memory management fixes, also some
adaptions to the final v4l2 api.

  Gerd

--- linux-2.5.45/drivers/media/video/video-buf.c	2002-10-31 14:03:59.000000000 +0100
+++ linux/drivers/media/video/video-buf.c	2002-10-31 14:20:27.000000000 +0100
@@ -26,6 +26,11 @@
 #include <asm/page.h>
 #include <asm/pgtable.h>
 
+#ifndef TryLockPage
+# include "linux/page-flags.h"
+# define TryLockPage TestSetPageLocked
+#endif
+
 #include "video-buf.h"
 
 static int debug = 0;
@@ -65,12 +70,12 @@
 	return NULL;
 }
 
-struct scatterlist *
+struct scatterlist*
 videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset)
 {
 	struct scatterlist *sglist;
 	int i = 0;
-	
+
 	if (NULL == pages[0])
 		return NULL;
 	sglist = kmalloc(sizeof(*sglist) * nr_pages, GFP_KERNEL);
@@ -80,21 +85,27 @@
 
 	if (PageHighMem(pages[0]))
 		/* DMA to highmem pages might not work */
-		goto err;
+		goto highmem;
 	sglist[0].page   = pages[0];
 	sglist[0].offset = offset;
 	sglist[0].length = PAGE_SIZE - offset;
 	for (i = 1; i < nr_pages; i++) {
 		if (NULL == pages[i])
-			goto err;
+			goto nopage;
 		if (PageHighMem(pages[i]))
-			goto err;
+			goto highmem;
 		sglist[i].page   = pages[i];
 		sglist[i].length = PAGE_SIZE;
 	}
 	return sglist;
 
- err:
+ nopage:
+	dprintk(2,"sgl: oops - no page\n");
+	kfree(sglist);
+	return NULL;
+
+ highmem:
+	dprintk(2,"sgl: oops - highmem page\n");
 	kfree(sglist);
 	return NULL;
 }
@@ -103,14 +114,18 @@
 {
 	int i;
 
+	dprintk(2,"lock start ...\n");
 	for (i = 0; i < nr_pages; i++)
-		if (TestSetPageLocked(pages[i]))
+		if (TryLockPage(pages[i]))
 			goto err;
+	dprintk(2,"lock ok\n");
 	return 0;
 
  err:
+	dprintk(2,"lock failed, unlock ...\n");
 	while (i > 0)
 		unlock_page(pages[--i]);
+	dprintk(2,"lock quit\n");
 	return -EINVAL;
 }
 
@@ -118,8 +133,10 @@
 {
 	int i;
 
+	dprintk(2,"unlock start ...\n");
 	for (i = 0; i < nr_pages; i++)
 		unlock_page(pages[i]);
+	dprintk(2,"unlock ok\n");
 	return 0;
 }
 
@@ -128,6 +145,7 @@
 int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction,
 			   unsigned long data, unsigned long size)
 {
+	unsigned long first,last;
 	int err, rw = 0;
 
 	dma->direction = direction;
@@ -137,25 +155,35 @@
 	default:                 BUG();
 	}
 
-	dma->offset   = data & PAGE_MASK;
-	dma->nr_pages = ((((data+size) & ~PAGE_MASK) -
-			  (data & ~PAGE_MASK)) >> PAGE_SHIFT) +1;
-	dma->pages    = kmalloc(dma->nr_pages * sizeof(struct page*),
-				GFP_KERNEL);
+	first = (data          & PAGE_MASK) >> PAGE_SHIFT;
+	last  = ((data+size-1) & PAGE_MASK) >> PAGE_SHIFT;
+	dma->offset   = data & ~PAGE_MASK;
+	dma->nr_pages = last-first+1;
+	dma->pages = kmalloc(dma->nr_pages * sizeof(struct page*),
+			     GFP_KERNEL);
 	if (NULL == dma->pages)
 		return -ENOMEM;
+	dprintk(1,"init user [0x%lx+0x%lx => %d pages]\n",
+		data,size,dma->nr_pages);
+
 	down_read(&current->mm->mmap_sem);
         err = get_user_pages(current,current->mm,
-			     data, dma->nr_pages,
-			     rw == READ, 0, /* don't force */
+			     data & PAGE_MASK, dma->nr_pages,
+			     rw == READ, 1, /* force */
 			     dma->pages, NULL);
 	up_read(&current->mm->mmap_sem);
-	return err;
+	if (err != dma->nr_pages) {
+		dma->nr_pages = (err >= 0) ? err : 0;
+		dprintk(1,"get_user_pages: err=%d [%d]\n",err,dma->nr_pages);
+		return err < 0 ? err : -EINVAL;
+	}
+	return 0;
 }
 
 int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction,
 			     int nr_pages)
 {
+	dprintk(1,"init kernel [%d pages]\n",nr_pages);
 	dma->direction = direction;
 	dma->vmalloc = vmalloc_32(nr_pages << PAGE_SHIFT);
 	if (NULL == dma->vmalloc) {
@@ -176,13 +204,14 @@
 	
 	if (dma->pages) {
 		if (0 != (err = videobuf_lock(dma->pages, dma->nr_pages))) {
-			dprintk(1,"videobuf_lock_pages: %d\n",err);
+			dprintk(1,"videobuf_lock: %d\n",err);
 			return err;
 		}
 		dma->sglist = videobuf_pages_to_sg(dma->pages, dma->nr_pages,
 						   dma->offset);
+		if (NULL == dma->sglist)
+			videobuf_unlock(dma->pages, dma->nr_pages);
 	}
-
 	if (dma->vmalloc) {
 		dma->sglist = videobuf_vmalloc_to_sg
 			(dma->vmalloc,dma->nr_pages);
@@ -215,7 +244,7 @@
 	dma->sglist = NULL;
 	dma->sglen = 0;
 	if (dma->pages)
-		videobuf_lock(dma->pages, dma->nr_pages);
+		videobuf_unlock(dma->pages, dma->nr_pages);
 	return 0;
 }
 
@@ -231,7 +260,6 @@
 		kfree(dma->pages);
 		dma->pages = NULL;
 	}
-
 	if (dma->vmalloc) {
 		vfree(dma->vmalloc);
 		dma->vmalloc = NULL;
@@ -286,16 +314,12 @@
 	if (0 == vb->baddr) {
 		/* no userspace addr -- kernel bounce buffer */
 		pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT;
-		dprintk(1,"kernel buf size=%ld (%d pages)\n",
-			vb->size,pages);
 		err = videobuf_dma_init_kernel(&vb->dma,PCI_DMA_FROMDEVICE,
 					       pages);
 		if (0 != err)
 			return err;
 	} else {
 		/* dma directly to userspace */
-		dprintk(1,"user buf addr=%08lx size=%ld\n",
-			vb->baddr,vb->bsize);
 		err = videobuf_dma_init_user(&vb->dma,PCI_DMA_FROMDEVICE,
 					     vb->baddr,vb->bsize);
 		if (0 != err)
@@ -314,7 +338,7 @@
 		    struct videobuf_queue_ops *ops,
 		    struct pci_dev *pci,
 		    spinlock_t *irqlock,
-		    int type,
+		    enum v4l2_buf_type type,
 		    int msize)
 {
 	memset(q,0,sizeof(*q));
@@ -329,6 +353,30 @@
 	INIT_LIST_HEAD(&q->stream);
 }
 
+int 
+videobuf_queue_is_busy(struct videobuf_queue *q)
+{
+	int i;
+	
+	if (q->reading)
+		return 1;
+	if (q->streaming)
+		return 1;
+	if (q->read_buf)
+		return 1;
+	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+		if (NULL == q->bufs[i])
+			continue;
+		if (q->bufs[i]->map)
+			return 1;
+		if (q->bufs[i]->state == STATE_QUEUED)
+			return 1;
+		if (q->bufs[i]->state == STATE_ACTIVE)
+			return 1;
+	}
+	return 0;
+}
+
 void
 videobuf_queue_cancel(struct file *file, struct videobuf_queue *q)
 {
@@ -358,15 +406,15 @@
 
 /* --------------------------------------------------------------------- */
 
-#ifdef HAVE_V4L2
 void
-videobuf_status(struct v4l2_buffer *b, struct videobuf_buffer *vb, int type)
+videobuf_status(struct v4l2_buffer *b, struct videobuf_buffer *vb,
+		enum v4l2_buf_type type)
 {
-	b->index  = vb->i;
-	b->type   = type;
-	b->offset = vb->boff;
-	b->length = vb->bsize;
-	b->flags  = 0;
+	b->index    = vb->i;
+	b->type     = type;
+	b->m.offset = vb->boff;
+	b->length   = vb->bsize;
+	b->flags    = 0;
 	if (vb->map)
 		b->flags |= V4L2_BUF_FLAG_MAPPED;
 	switch (vb->state) {
@@ -384,12 +432,7 @@
 		/* nothing */
 		break;
 	}
-	if (!(vb->field & VBUF_FIELD_INTER)) {
-		if (vb->field & VBUF_FIELD_ODD)
-			b->flags |= V4L2_BUF_FLAG_TOPFIELD;
-		if (vb->field & VBUF_FIELD_EVEN)
-			b->flags |= V4L2_BUF_FLAG_BOTFIELD;
-	}
+	b->field     = vb->field;
 	b->timestamp = vb->ts;
 	b->bytesused = vb->size;
 	b->sequence  = vb->field_count >> 1;
@@ -401,7 +444,7 @@
 {
 	int size,count,retval;
 
-	if ((req->type & V4L2_BUF_TYPE_field) != q->type)
+	if (req->type != q->type)
 		return -EINVAL;
 	if (req->count < 1)
 		return -EINVAL;
@@ -428,11 +471,11 @@
 int
 videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b)
 {
-	if ((b->type & V4L2_BUF_TYPE_field) != q->type)
+	if (unlikely(b->type != q->type))
 		return -EINVAL;
-	if (b->index < 0 || b->index >= VIDEO_MAX_FRAME)
+	if (unlikely(b->index < 0 || b->index >= VIDEO_MAX_FRAME))
 		return -EINVAL;
-	if (NULL == q->bufs[b->index])
+	if (unlikely(NULL == q->bufs[b->index]))
 		return -EINVAL;
 	videobuf_status(b,q->bufs[b->index],q->type);
 	return 0;
@@ -444,7 +487,6 @@
 {
 	struct videobuf_buffer *buf;
 	unsigned long flags;
-	int field = 0;
 	int retval;
 
 	down(&q->lock);
@@ -452,7 +494,7 @@
 	if (q->reading)
 		goto done;
 	retval = -EINVAL;
-	if ((b->type & V4L2_BUF_TYPE_field) != q->type)
+	if (b->type != q->type)
 		goto done;
 	if (b->index < 0 || b->index >= VIDEO_MAX_FRAME)
 		goto done;
@@ -465,11 +507,7 @@
 	    buf->state == STATE_ACTIVE)
 		goto done;
 
-	if (b->flags & V4L2_BUF_FLAG_TOPFIELD)
-		field |= VBUF_FIELD_ODD;
-	if (b->flags & V4L2_BUF_FLAG_BOTFIELD)
-		field |= VBUF_FIELD_EVEN;
-	retval = q->ops->buf_prepare(file,buf,field);
+	retval = q->ops->buf_prepare(file,buf);
 	if (0 != retval)
 		goto done;
 	
@@ -498,7 +536,7 @@
 	if (q->reading)
 		goto done;
 	retval = -EINVAL;
-	if ((b->type & V4L2_BUF_TYPE_field) != q->type)
+	if (b->type != q->type)
 		goto done;
 	if (list_empty(&q->stream))
 		goto done;
@@ -526,7 +564,6 @@
 	up(&q->lock);
 	return retval;
 }
-#endif /* HAVE_V4L2 */
 
 int videobuf_streamon(struct file *file, struct videobuf_queue *q)
 {
@@ -586,7 +623,7 @@
 
 	q->read_buf->baddr = (unsigned long)data;
         q->read_buf->bsize = count;
-	retval = q->ops->buf_prepare(file,q->read_buf,0);
+	retval = q->ops->buf_prepare(file,q->read_buf);
 	if (0 != retval)
 		goto done;
 	
@@ -631,7 +668,7 @@
 		q->read_buf = videobuf_alloc(q->msize);
 		if (NULL == q->read_buf)
 			goto done;
-		retval = q->ops->buf_prepare(file,q->read_buf,0);
+		retval = q->ops->buf_prepare(file,q->read_buf);
 		if (0 != retval)
 			goto done;
 		q->ops->buf_queue(file,q->read_buf);
@@ -683,7 +720,7 @@
 	if (err)
 		return err;
 	for (i = 0; i < count; i++) {
-		err = q->ops->buf_prepare(file,q->bufs[i],0);
+		err = q->ops->buf_prepare(file,q->bufs[i]);
 		if (err)
 			return err;
 		list_add_tail(&q->bufs[i]->stream, &q->stream);
@@ -1008,6 +1045,8 @@
 /* --------------------------------------------------------------------- */
 
 EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg);
+EXPORT_SYMBOL_GPL(videobuf_lock);
+EXPORT_SYMBOL_GPL(videobuf_unlock);
 
 EXPORT_SYMBOL_GPL(videobuf_dma_init_user);
 EXPORT_SYMBOL_GPL(videobuf_dma_init_kernel);
@@ -1022,14 +1061,13 @@
 
 EXPORT_SYMBOL_GPL(videobuf_queue_init);
 EXPORT_SYMBOL_GPL(videobuf_queue_cancel);
+EXPORT_SYMBOL_GPL(videobuf_queue_is_busy);
 
-#ifdef HAVE_V4L2
 EXPORT_SYMBOL_GPL(videobuf_status);
 EXPORT_SYMBOL_GPL(videobuf_reqbufs);
 EXPORT_SYMBOL_GPL(videobuf_querybuf);
 EXPORT_SYMBOL_GPL(videobuf_qbuf);
 EXPORT_SYMBOL_GPL(videobuf_dqbuf);
-#endif
 EXPORT_SYMBOL_GPL(videobuf_streamon);
 EXPORT_SYMBOL_GPL(videobuf_streamoff);
 
--- linux-2.5.45/drivers/media/video/video-buf.h	2002-10-31 14:04:05.000000000 +0100
+++ linux/drivers/media/video/video-buf.h	2002-10-31 14:20:27.000000000 +0100
@@ -28,12 +28,14 @@
 struct scatterlist* videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages);
 
 /*
- * Return a scatterlist for a an array of userpages (NULL on errors).  Memory
- * for the scatterlist is allocated using kmalloc.  The caller must
- * free the memory.
+ * Return a scatterlist for a an array of userpages (NULL on errors).
+ * Memory for the scatterlist is allocated using kmalloc.  The caller
+ * must free the memory.
  */
-struct scatterlist *videobuf_pages_to_sg(struct page **pages, int nr_pages,
+struct scatterlist* videobuf_pages_to_sg(struct page **pages, int nr_pages,
 					 int offset);
+int videobuf_lock(struct page **pages, int nr_pages);
+int videobuf_unlock(struct page **pages, int nr_pages);
 
 /* --------------------------------------------------------------------- */
 
@@ -58,8 +60,8 @@
 
 struct videobuf_dmabuf {
 	/* for userland buffer */
-	struct page         **pages;
 	int                 offset;
+	struct page         **pages;
 
 	/* for kernel buffers */
 	void                *vmalloc;
@@ -115,10 +117,6 @@
 	struct videobuf_queue *q;
 };
 
-#define VBUF_FIELD_EVEN  1
-#define VBUF_FIELD_ODD   2
-#define VBUF_FIELD_INTER 4
-
 enum videobuf_state {
 	STATE_NEEDS_INIT = 0,
 	STATE_PREPARED   = 1,
@@ -136,30 +134,27 @@
 	int                     width;
 	int                     height;
 	long                    size;
-	int                     field;
+	enum v4l2_field         field;
 	enum videobuf_state     state;
 	struct videobuf_dmabuf  dma;
 	struct list_head        stream;  /* QBUF/DQBUF list */
 
 	/* for mmap'ed buffers */
-	unsigned long  boff;             /* buffer offset (mmap) */
-	unsigned long  bsize;            /* buffer size */
-	unsigned long  baddr;            /* buffer addr (userland ptr!) */
+	off_t                   boff;    /* buffer offset (mmap) */
+	size_t                  bsize;   /* buffer size */
+	unsigned long           baddr;   /* buffer addr (userland ptr!) */
 	struct videobuf_mapping *map;
 
 	/* touched by irq handler */
 	struct list_head        queue;
 	wait_queue_head_t       done;
 	int                     field_count;
-#ifdef HAVE_V4L2
-	stamp_t                 ts;
-#endif
+	struct timeval          ts;
 };
 
 struct videobuf_queue_ops {
 	int (*buf_setup)(struct file *file, int *count, int *size);
-	int (*buf_prepare)(struct file *file,struct videobuf_buffer *vb,
-			   int field);
+	int (*buf_prepare)(struct file *file,struct videobuf_buffer *vb);
 	void (*buf_queue)(struct file *file,struct videobuf_buffer *vb);
 	void (*buf_release)(struct file *file,struct videobuf_buffer *vb);
 };
@@ -169,7 +164,7 @@
 	spinlock_t                 *irqlock;
 	struct pci_dev             *pci;
 
-	int                        type;
+	enum v4l2_buf_type         type;
 	int                        msize;
 	struct videobuf_buffer     *bufs[VIDEO_MAX_FRAME];
 	struct videobuf_queue_ops  *ops;
@@ -191,12 +186,12 @@
 void videobuf_queue_init(struct videobuf_queue *q,
 			 struct videobuf_queue_ops *ops,
 			 struct pci_dev *pci, spinlock_t *irqlock,
-			 int type, int msize);
+			 enum v4l2_buf_type type, int msize);
+int  videobuf_queue_is_busy(struct videobuf_queue *q);
 void videobuf_queue_cancel(struct file *file, struct videobuf_queue *q);
 
-#ifdef HAVE_V4L2
 void videobuf_status(struct v4l2_buffer *b, struct videobuf_buffer *vb,
-		     int type);
+		     enum v4l2_buf_type type);
 int videobuf_reqbufs(struct file *file, struct videobuf_queue *q,
 		     struct v4l2_requestbuffers *req);
 int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b);
@@ -204,7 +199,6 @@
 		  struct v4l2_buffer *b);
 int videobuf_dqbuf(struct file *file, struct videobuf_queue *q,
 		   struct v4l2_buffer *b);
-#endif
 int videobuf_streamon(struct file *file, struct videobuf_queue *q);
 int videobuf_streamoff(struct file *file, struct videobuf_queue *q);
 

-- 
You can't please everybody.  And usually if you _try_ to please
everybody, the end result is one big mess.
				-- Linus Torvalds, 2002-04-20

                 reply	other threads:[~2002-10-31 15:24 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20021031161234.GA17340@bytesex.org \
    --to=kraxel@bytesex.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=torvalds@transmeta.com \
    --cc=video4linux-list@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.