summaryrefslogtreecommitdiffstats
path: root/drivers/media/video/vivi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/vivi.c')
-rw-r--r--drivers/media/video/vivi.c351
1 files changed, 48 insertions, 303 deletions
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 3ef4d0159c3..b532aa280a1 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -25,6 +25,7 @@
#include <linux/pci.h>
#include <linux/random.h>
#include <linux/version.h>
+#include <linux/mutex.h>
#include <linux/videodev2.h>
#include <linux/dma-mapping.h>
#ifdef CONFIG_VIDEO_V4L1_COMPAT
@@ -32,7 +33,7 @@
#include <linux/videodev.h>
#endif
#include <linux/interrupt.h>
-#include <media/video-buf.h>
+#include <media/videobuf-vmalloc.h>
#include <media/v4l2-common.h>
#include <linux/kthread.h>
#include <linux/highmem.h>
@@ -144,10 +145,6 @@ struct vivi_buffer {
struct videobuf_buffer vb;
struct vivi_fmt *fmt;
-
-#ifdef CONFIG_VIVI_SCATTER
- struct sg_to_addr *to_addr;
-#endif
};
struct vivi_dmaqueue {
@@ -168,12 +165,11 @@ static LIST_HEAD(vivi_devlist);
struct vivi_dev {
struct list_head vivi_devlist;
- struct semaphore lock;
+ struct mutex lock;
int users;
/* various device info */
- unsigned int resources;
struct video_device vfd;
struct vivi_dmaqueue vidq;
@@ -232,91 +228,25 @@ static u8 bars[8][3] = {
#define TSTAMP_MAX_Y TSTAMP_MIN_Y+15
#define TSTAMP_MIN_X 64
-#ifdef CONFIG_VIVI_SCATTER
-static void prep_to_addr(struct sg_to_addr to_addr[],
- struct videobuf_buffer *vb)
-{
- int i, pos=0;
-
- for (i=0;i<vb->dma.nr_pages;i++) {
- to_addr[i].sg=&vb->dma.sglist[i];
- to_addr[i].pos=pos;
- pos += vb->dma.sglist[i].length;
- }
-}
-
-static int get_addr_pos(int pos, int pages, struct sg_to_addr to_addr[])
-{
- int p1=0,p2=pages-1,p3=pages/2;
-
- /* Sanity test */
- BUG_ON (pos>=to_addr[p2].pos+to_addr[p2].sg->length);
-
- while (p1+1<p2) {
- if (pos < to_addr[p3].pos) {
- p2=p3;
- } else {
- p1=p3;
- }
- p3=(p1+p2)/2;
- }
- if (pos >= to_addr[p2].pos)
- p1=p2;
-
- return (p1);
-}
-#endif
-
-#ifdef CONFIG_VIVI_SCATTER
-static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
- int hmax, int line, char *timestr)
-#else
static void gen_line(char *basep,int inipos,int wmax,
- int hmax, int line, char *timestr)
-#endif
+ int hmax, int line, int count, char *timestr)
{
int w,i,j,pos=inipos,y;
char *p,*s;
u8 chr,r,g,b,color;
-#ifdef CONFIG_VIVI_SCATTER
- int pgpos,oldpg;
- char *basep;
- struct page *pg;
-
- unsigned long flags;
- spinlock_t spinlock;
-
- spin_lock_init(&spinlock);
-
- /* Get first addr pointed to pixel position */
- oldpg=get_addr_pos(pos,pages,to_addr);
- pg=pfn_to_page(sg_dma_address(to_addr[oldpg].sg) >> PAGE_SHIFT);
- spin_lock_irqsave(&spinlock,flags);
- basep = kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[oldpg].sg->offset;
-#endif
/* We will just duplicate the second pixel at the packet */
wmax/=2;
/* Generate a standard color bar pattern */
for (w=0;w<wmax;w++) {
- r=bars[w*7/wmax][0];
- g=bars[w*7/wmax][1];
- b=bars[w*7/wmax][2];
+ int colorpos=((w+count)*8/(wmax+1)) % 8;
+ r=bars[colorpos][0];
+ g=bars[colorpos][1];
+ b=bars[colorpos][2];
for (color=0;color<4;color++) {
-#ifdef CONFIG_VIVI_SCATTER
- pgpos=get_addr_pos(pos,pages,to_addr);
- if (pgpos!=oldpg) {
- pg=pfn_to_page(sg_dma_address(to_addr[pgpos].sg) >> PAGE_SHIFT);
- kunmap_atomic(basep, KM_BOUNCE_READ);
- basep= kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[pgpos].sg->offset;
- oldpg=pgpos;
- }
- p=basep+pos-to_addr[pgpos].pos;
-#else
p=basep+pos;
-#endif
switch (color) {
case 0:
@@ -361,23 +291,7 @@ static void gen_line(char *basep,int inipos,int wmax,
pos=inipos+j*2;
for (color=0;color<4;color++) {
-#ifdef CONFIG_VIVI_SCATTER
- pgpos=get_addr_pos(pos,pages,to_addr);
- if (pgpos!=oldpg) {
- pg=pfn_to_page(sg_dma_address(
- to_addr[pgpos].sg)
- >> PAGE_SHIFT);
- kunmap_atomic(basep,
- KM_BOUNCE_READ);
- basep= kmap_atomic(pg,
- KM_BOUNCE_READ)+
- to_addr[pgpos].sg->offset;
- oldpg=pgpos;
- }
- p=basep+pos-to_addr[pgpos].pos;
-#else
p=basep+pos;
-#endif
y=TO_Y(r,g,b);
@@ -402,12 +316,7 @@ static void gen_line(char *basep,int inipos,int wmax,
end:
-#ifdef CONFIG_VIVI_SCATTER
- kunmap_atomic(basep, KM_BOUNCE_READ);
- spin_unlock_irqrestore(&spinlock,flags);
-#else
return;
-#endif
}
static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
{
@@ -415,47 +324,27 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
int hmax = buf->vb.height;
int wmax = buf->vb.width;
struct timeval ts;
-#ifdef CONFIG_VIVI_SCATTER
- struct sg_to_addr *to_addr=buf->to_addr;
- struct videobuf_buffer *vb=&buf->vb;
-#else
- char *tmpbuf;
-#endif
+ char *tmpbuf = kmalloc(wmax*2,GFP_KERNEL);
+ void *vbuf=videobuf_to_vmalloc (&buf->vb);
+ /* FIXME: move to dev struct */
+ static int mv_count=0;
-#ifdef CONFIG_VIVI_SCATTER
- /* Test if DMA mapping is ready */
- if (!sg_dma_address(&vb->dma.sglist[0]))
+ if (!tmpbuf)
return;
- prep_to_addr(to_addr,vb);
-
- /* Check if there is enough memory */
- BUG_ON(buf->vb.dma.nr_pages << PAGE_SHIFT < (buf->vb.width*buf->vb.height)*2);
-#else
- if (buf->vb.dma.varea) {
- tmpbuf=kmalloc (wmax*2, GFP_KERNEL);
- } else {
- tmpbuf=buf->vb.dma.vmalloc;
- }
-
-#endif
-
for (h=0;h<hmax;h++) {
-#ifdef CONFIG_VIVI_SCATTER
- gen_line(to_addr,pos,vb->dma.nr_pages,wmax,hmax,h,dev->timestr);
-#else
- if (buf->vb.dma.varea) {
- gen_line(tmpbuf,0,wmax,hmax,h,dev->timestr);
- /* FIXME: replacing to __copy_to_user */
- if (copy_to_user(buf->vb.dma.varea+pos,tmpbuf,wmax*2)!=0)
- dprintk(2,"vivifill copy_to_user failed.\n");
- } else {
- gen_line(tmpbuf,pos,wmax,hmax,h,dev->timestr);
- }
-#endif
+ gen_line(tmpbuf,0,wmax,hmax,h,mv_count,
+ dev->timestr);
+ /* FIXME: replacing to __copy_to_user */
+ if (copy_to_user(vbuf+pos,tmpbuf,wmax*2)!=0)
+ dprintk(2,"vivifill copy_to_user failed.\n");
pos += wmax*2;
}
+ mv_count++;
+
+ kfree(tmpbuf);
+
/* Updates stream time */
dev->us+=jiffies_to_usecs(jiffies-dev->jiffies);
@@ -478,7 +367,7 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
dev->h,dev->m,dev->s,(dev->us+500)/1000);
dprintk(2,"vivifill at %s: Buffer 0x%08lx size= %d\n",dev->timestr,
- (unsigned long)buf->vb.dma.varea,pos);
+ (unsigned long)tmpbuf,pos);
/* Advice that buffer was filled */
buf->vb.state = STATE_DONE;
@@ -618,7 +507,6 @@ static void vivi_stop_thread(struct vivi_dmaqueue *dma_q)
static int restart_video_queue(struct vivi_dmaqueue *dma_q)
{
struct vivi_buffer *buf, *prev;
- struct list_head *item;
dprintk(1,"%s dma_q=0x%08lx\n",__FUNCTION__,(unsigned long)dma_q);
@@ -632,9 +520,7 @@ static int restart_video_queue(struct vivi_dmaqueue *dma_q)
// vivi_start_thread(dma_q);
/* cancel all outstanding capture / vbi requests */
- list_for_each(item,&dma_q->active) {
- buf = list_entry(item, struct vivi_buffer, vb.queue);
-
+ list_for_each_entry_safe(buf, prev, &dma_q->active, vb.queue) {
list_del(&buf->vb.queue);
buf->vb.state = STATE_ERROR;
wake_up(&buf->vb.done);
@@ -706,8 +592,12 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
if (0 == *count)
*count = 32;
+
while (*size * *count > vid_limit * 1024 * 1024)
(*count)--;
+
+ dprintk(1,"%s, count=%d, size=%d\n",__FUNCTION__,*count, *size);
+
return 0;
}
@@ -718,15 +608,8 @@ static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
if (in_interrupt())
BUG();
-#ifdef CONFIG_VIVI_SCATTER
- /*FIXME: Maybe a spinlock is required here */
- kfree(buf->to_addr);
- buf->to_addr=NULL;
-#endif
-
videobuf_waiton(&buf->vb,0,0);
- videobuf_dma_unmap(vq, &buf->vb.dma);
- videobuf_dma_free(&buf->vb.dma);
+ videobuf_vmalloc_free(&buf->vb);
buf->vb.state = STATE_NEEDS_INIT;
}
@@ -740,7 +623,7 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
struct vivi_buffer *buf = container_of(vb,struct vivi_buffer,vb);
int rc, init_buffer = 0;
-// dprintk(1,"%s, field=%d\n",__FUNCTION__,field);
+ dprintk(1,"%s, field=%d\n",__FUNCTION__,field);
BUG_ON(NULL == fh->fmt);
if (fh->width < 48 || fh->width > norm_maxw() ||
@@ -768,12 +651,6 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
buf->vb.state = STATE_PREPARED;
-#ifdef CONFIG_VIVI_SCATTER
- if (NULL == (buf->to_addr = kmalloc(sizeof(*buf->to_addr) * vb->dma.nr_pages,GFP_KERNEL))) {
- rc=-ENOMEM;
- goto fail;
- }
-#endif
return 0;
fail:
@@ -838,88 +715,14 @@ static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb
free_buffer(vq,buf);
}
-#ifdef CONFIG_VIVI_SCATTER
-static int vivi_map_sg(void *dev, struct scatterlist *sg, int nents,
- int direction)
-{
- int i;
-
- dprintk(1,"%s, number of pages=%d\n",__FUNCTION__,nents);
- BUG_ON(direction == DMA_NONE);
-
- for (i = 0; i < nents; i++ ) {
- BUG_ON(!sg[i].page);
-
- sg_dma_address(&sg[i]) = page_to_phys(sg[i].page) + sg[i].offset;
- }
-
- return nents;
-}
-
-static int vivi_unmap_sg(void *dev,struct scatterlist *sglist,int nr_pages,
- int direction)
-{
- dprintk(1,"%s\n",__FUNCTION__);
- return 0;
-}
-
-static int vivi_dma_sync_sg(void *dev,struct scatterlist *sglist, int nr_pages,
- int direction)
-{
-// dprintk(1,"%s\n",__FUNCTION__);
-
-// flush_write_buffers();
- return 0;
-}
-#endif
-
static struct videobuf_queue_ops vivi_video_qops = {
.buf_setup = buffer_setup,
.buf_prepare = buffer_prepare,
.buf_queue = buffer_queue,
.buf_release = buffer_release,
-
- /* Non-pci handling routines */
-// .vb_map_sg = vivi_map_sg,
-// .vb_dma_sync_sg = vivi_dma_sync_sg,
-// .vb_unmap_sg = vivi_unmap_sg,
};
/* ------------------------------------------------------------------
- IOCTL handling
- ------------------------------------------------------------------*/
-
-
-static int res_get(struct vivi_dev *dev, struct vivi_fh *fh)
-{
- /* is it free? */
- down(&dev->lock);
- if (dev->resources) {
- /* no, someone else uses it */
- up(&dev->lock);
- return 0;
- }
- /* it's free, grab it */
- dev->resources =1;
- dprintk(1,"res: get\n");
- up(&dev->lock);
- return 1;
-}
-
-static int res_locked(struct vivi_dev *dev)
-{
- return (dev->resources);
-}
-
-static void res_free(struct vivi_dev *dev, struct vivi_fh *fh)
-{
- down(&dev->lock);
- dev->resources = 0;
- dprintk(1,"res: put\n");
- up(&dev->lock);
-}
-
-/* ------------------------------------------------------------------
IOCTL vidioc handling
------------------------------------------------------------------*/
static int vidioc_querycap (struct file *file, void *priv,
@@ -979,8 +782,7 @@ static int vidioc_try_fmt_cap (struct file *file, void *priv,
field = f->fmt.pix.field;
if (field == V4L2_FIELD_ANY) {
-// field=V4L2_FIELD_INTERLACED;
- field=V4L2_FIELD_SEQ_TB;
+ field=V4L2_FIELD_INTERLACED;
} else if (V4L2_FIELD_INTERLACED != field) {
dprintk(1,"Field type invalid.\n");
return -EINVAL;
@@ -1058,57 +860,33 @@ static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p)
static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf)
{
struct vivi_fh *fh=priv;
- struct videobuf_queue *q=&fh->vb_vidq;
- struct v4l2_requestbuffers req;
- unsigned int i;
- int ret;
-
- req.type = q->type;
- req.count = 8;
- req.memory = V4L2_MEMORY_MMAP;
- ret = videobuf_reqbufs(q,&req);
- if (ret < 0)
- return (ret);
- mbuf->frames = req.count;
- mbuf->size = 0;
- for (i = 0; i < mbuf->frames; i++) {
- mbuf->offsets[i] = q->bufs[i]->boff;
- mbuf->size += q->bufs[i]->bsize;
- }
- return (0);
+ return videobuf_cgmbuf (&fh->vb_vidq, mbuf, 8);
}
#endif
static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
{
struct vivi_fh *fh=priv;
- struct vivi_dev *dev = fh->dev;
if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
if (i != fh->type)
return -EINVAL;
- if (!res_get(dev,fh))
- return -EBUSY;
- return (videobuf_streamon(&fh->vb_vidq));
+ return videobuf_streamon(&fh->vb_vidq);
}
static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
{
struct vivi_fh *fh=priv;
- struct vivi_dev *dev = fh->dev;
if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
if (i != fh->type)
return -EINVAL;
- videobuf_streamoff(&fh->vb_vidq);
- res_free(dev,fh);
-
- return (0);
+ return videobuf_streamoff(&fh->vb_vidq);
}
static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *i)
@@ -1201,31 +979,25 @@ static int vidioc_s_ctrl (struct file *file, void *priv,
static int vivi_open(struct inode *inode, struct file *file)
{
int minor = iminor(inode);
- struct vivi_dev *h,*dev = NULL;
+ struct vivi_dev *dev;
struct vivi_fh *fh;
- struct list_head *list;
- enum v4l2_buf_type type = 0;
int i;
printk(KERN_DEBUG "vivi: open called (minor=%d)\n",minor);
- list_for_each(list,&vivi_devlist) {
- h = list_entry(list, struct vivi_dev, vivi_devlist);
- if (h->vfd.minor == minor) {
- dev = h;
- type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- }
- }
- if (NULL == dev)
- return -ENODEV;
+ list_for_each_entry(dev, &vivi_devlist, vivi_devlist)
+ if (dev->vfd.minor == minor)
+ goto found;
+ return -ENODEV;
+found:
/* If more than one user, mutex should be added */
dev->users++;
- dprintk(1,"open minor=%d type=%s users=%d\n",
- minor,v4l2_type_names[type],dev->users);
+ dprintk(1, "open minor=%d type=%s users=%d\n", minor,
+ v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users);
/* allocate + initialize per filehandle data */
fh = kzalloc(sizeof(*fh),GFP_KERNEL);
@@ -1260,19 +1032,11 @@ static int vivi_open(struct inode *inode, struct file *file)
sprintf(dev->timestr,"%02d:%02d:%02d:%03d",
dev->h,dev->m,dev->s,(dev->us+500)/1000);
-#ifdef CONFIG_VIVI_SCATTER
- videobuf_queue_init(&fh->vb_vidq,VIDEOBUF_DMA_SCATTER, &vivi_video_qops,
+ videobuf_queue_vmalloc_init(&fh->vb_vidq, &vivi_video_qops,
NULL, NULL,
fh->type,
V4L2_FIELD_INTERLACED,
sizeof(struct vivi_buffer),fh);
-#else
- videobuf_queue_init(&fh->vb_vidq, &vivi_video_qops,
- NULL, NULL,
- fh->type,
- V4L2_FIELD_INTERLACED,
- sizeof(struct vivi_buffer),fh);
-#endif
return 0;
}
@@ -1283,9 +1047,7 @@ vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
struct vivi_fh *fh = file->private_data;
if (fh->type==V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- if (res_locked(fh->dev))
- return -EBUSY;
- return videobuf_read_one(&fh->vb_vidq, data, count, ppos,
+ return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0,
file->f_flags & O_NONBLOCK);
}
return 0;
@@ -1295,31 +1057,14 @@ static unsigned int
vivi_poll(struct file *file, struct poll_table_struct *wait)
{
struct vivi_fh *fh = file->private_data;
- struct vivi_buffer *buf;
+ struct videobuf_queue *q = &fh->vb_vidq;
dprintk(1,"%s\n",__FUNCTION__);
if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
return POLLERR;
- if (res_get(fh->dev,fh)) {
- dprintk(1,"poll: mmap interface\n");
- /* streaming capture */
- if (list_empty(&fh->vb_vidq.stream))
- return POLLERR;
- buf = list_entry(fh->vb_vidq.stream.next,struct vivi_buffer,vb.stream);
- } else {
- dprintk(1,"poll: read() interface\n");
- /* read() capture */
- buf = (struct vivi_buffer*)fh->vb_vidq.read_buf;
- if (NULL == buf)
- return POLLERR;
- }
- poll_wait(file, &buf->vb.done, wait);
- if (buf->vb.state == STATE_DONE ||
- buf->vb.state == STATE_ERROR)
- return POLLIN|POLLRDNORM;
- return 0;
+ return videobuf_poll_stream(file, q, wait);
}
static int vivi_release(struct inode *inode, struct file *file)
@@ -1367,7 +1112,7 @@ static const struct file_operations vivi_fops = {
.read = vivi_read,
.poll = vivi_poll,
.ioctl = video_ioctl2, /* V4L2 ioctl handler */
- .mmap = vivi_mmap,
+ .mmap = vivi_mmap,
.llseek = no_llseek,
};
@@ -1423,7 +1168,7 @@ static int __init vivi_init(void)
init_waitqueue_head(&dev->vidq.wq);
/* initialize locks */
- init_MUTEX(&dev->lock);
+ mutex_init(&dev->lock);
dev->vidq.timeout.function = vivi_vid_timeout;
dev->vidq.timeout.data = (unsigned long)dev;