xref: /openbmc/linux/drivers/media/usb/au0828/au0828-vbi.c (revision 83afb32aa9d8cc77049c0e4e124e3bed8b88428f)
10c0d06caSMauro Carvalho Chehab /*
20c0d06caSMauro Carvalho Chehab    au0828-vbi.c - VBI driver for au0828
30c0d06caSMauro Carvalho Chehab 
40c0d06caSMauro Carvalho Chehab    Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
50c0d06caSMauro Carvalho Chehab 
60c0d06caSMauro Carvalho Chehab    This work was sponsored by GetWellNetwork Inc.
70c0d06caSMauro Carvalho Chehab 
80c0d06caSMauro Carvalho Chehab    This program is free software; you can redistribute it and/or modify
90c0d06caSMauro Carvalho Chehab    it under the terms of the GNU General Public License as published by
100c0d06caSMauro Carvalho Chehab    the Free Software Foundation; either version 2 of the License, or
110c0d06caSMauro Carvalho Chehab    (at your option) any later version.
120c0d06caSMauro Carvalho Chehab 
130c0d06caSMauro Carvalho Chehab    This program is distributed in the hope that it will be useful,
140c0d06caSMauro Carvalho Chehab    but WITHOUT ANY WARRANTY; without even the implied warranty of
150c0d06caSMauro Carvalho Chehab    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
160c0d06caSMauro Carvalho Chehab    GNU General Public License for more details.
170c0d06caSMauro Carvalho Chehab 
180c0d06caSMauro Carvalho Chehab    You should have received a copy of the GNU General Public License
190c0d06caSMauro Carvalho Chehab    along with this program; if not, write to the Free Software
200c0d06caSMauro Carvalho Chehab    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
210c0d06caSMauro Carvalho Chehab    02110-1301, USA.
220c0d06caSMauro Carvalho Chehab  */
230c0d06caSMauro Carvalho Chehab 
24*83afb32aSMauro Carvalho Chehab #include "au0828.h"
25*83afb32aSMauro Carvalho Chehab 
260c0d06caSMauro Carvalho Chehab #include <linux/kernel.h>
270c0d06caSMauro Carvalho Chehab #include <linux/module.h>
280c0d06caSMauro Carvalho Chehab #include <linux/init.h>
290c0d06caSMauro Carvalho Chehab #include <linux/slab.h>
300c0d06caSMauro Carvalho Chehab 
310c0d06caSMauro Carvalho Chehab static unsigned int vbibufs = 5;
320c0d06caSMauro Carvalho Chehab module_param(vbibufs, int, 0644);
330c0d06caSMauro Carvalho Chehab MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32");
340c0d06caSMauro Carvalho Chehab 
350c0d06caSMauro Carvalho Chehab /* ------------------------------------------------------------------ */
360c0d06caSMauro Carvalho Chehab 
370c0d06caSMauro Carvalho Chehab static void
380c0d06caSMauro Carvalho Chehab free_buffer(struct videobuf_queue *vq, struct au0828_buffer *buf)
390c0d06caSMauro Carvalho Chehab {
400c0d06caSMauro Carvalho Chehab 	struct au0828_fh     *fh  = vq->priv_data;
410c0d06caSMauro Carvalho Chehab 	struct au0828_dev    *dev = fh->dev;
420c0d06caSMauro Carvalho Chehab 	unsigned long flags = 0;
430c0d06caSMauro Carvalho Chehab 	if (in_interrupt())
440c0d06caSMauro Carvalho Chehab 		BUG();
450c0d06caSMauro Carvalho Chehab 
460c0d06caSMauro Carvalho Chehab 	/* We used to wait for the buffer to finish here, but this didn't work
470c0d06caSMauro Carvalho Chehab 	   because, as we were keeping the state as VIDEOBUF_QUEUED,
480c0d06caSMauro Carvalho Chehab 	   videobuf_queue_cancel marked it as finished for us.
490c0d06caSMauro Carvalho Chehab 	   (Also, it could wedge forever if the hardware was misconfigured.)
500c0d06caSMauro Carvalho Chehab 
510c0d06caSMauro Carvalho Chehab 	   This should be safe; by the time we get here, the buffer isn't
520c0d06caSMauro Carvalho Chehab 	   queued anymore. If we ever start marking the buffers as
530c0d06caSMauro Carvalho Chehab 	   VIDEOBUF_ACTIVE, it won't be, though.
540c0d06caSMauro Carvalho Chehab 	*/
550c0d06caSMauro Carvalho Chehab 	spin_lock_irqsave(&dev->slock, flags);
560c0d06caSMauro Carvalho Chehab 	if (dev->isoc_ctl.vbi_buf == buf)
570c0d06caSMauro Carvalho Chehab 		dev->isoc_ctl.vbi_buf = NULL;
580c0d06caSMauro Carvalho Chehab 	spin_unlock_irqrestore(&dev->slock, flags);
590c0d06caSMauro Carvalho Chehab 
600c0d06caSMauro Carvalho Chehab 	videobuf_vmalloc_free(&buf->vb);
610c0d06caSMauro Carvalho Chehab 	buf->vb.state = VIDEOBUF_NEEDS_INIT;
620c0d06caSMauro Carvalho Chehab }
630c0d06caSMauro Carvalho Chehab 
640c0d06caSMauro Carvalho Chehab static int
650c0d06caSMauro Carvalho Chehab vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
660c0d06caSMauro Carvalho Chehab {
670c0d06caSMauro Carvalho Chehab 	struct au0828_fh     *fh  = q->priv_data;
680c0d06caSMauro Carvalho Chehab 	struct au0828_dev    *dev = fh->dev;
690c0d06caSMauro Carvalho Chehab 
700c0d06caSMauro Carvalho Chehab 	*size = dev->vbi_width * dev->vbi_height * 2;
710c0d06caSMauro Carvalho Chehab 
720c0d06caSMauro Carvalho Chehab 	if (0 == *count)
730c0d06caSMauro Carvalho Chehab 		*count = vbibufs;
740c0d06caSMauro Carvalho Chehab 	if (*count < 2)
750c0d06caSMauro Carvalho Chehab 		*count = 2;
760c0d06caSMauro Carvalho Chehab 	if (*count > 32)
770c0d06caSMauro Carvalho Chehab 		*count = 32;
780c0d06caSMauro Carvalho Chehab 	return 0;
790c0d06caSMauro Carvalho Chehab }
800c0d06caSMauro Carvalho Chehab 
810c0d06caSMauro Carvalho Chehab static int
820c0d06caSMauro Carvalho Chehab vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
830c0d06caSMauro Carvalho Chehab 	    enum v4l2_field field)
840c0d06caSMauro Carvalho Chehab {
850c0d06caSMauro Carvalho Chehab 	struct au0828_fh     *fh  = q->priv_data;
860c0d06caSMauro Carvalho Chehab 	struct au0828_dev    *dev = fh->dev;
870c0d06caSMauro Carvalho Chehab 	struct au0828_buffer *buf = container_of(vb, struct au0828_buffer, vb);
880c0d06caSMauro Carvalho Chehab 	int                  rc = 0;
890c0d06caSMauro Carvalho Chehab 
900c0d06caSMauro Carvalho Chehab 	buf->vb.size = dev->vbi_width * dev->vbi_height * 2;
910c0d06caSMauro Carvalho Chehab 
920c0d06caSMauro Carvalho Chehab 	if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
930c0d06caSMauro Carvalho Chehab 		return -EINVAL;
940c0d06caSMauro Carvalho Chehab 
950c0d06caSMauro Carvalho Chehab 	buf->vb.width  = dev->vbi_width;
960c0d06caSMauro Carvalho Chehab 	buf->vb.height = dev->vbi_height;
970c0d06caSMauro Carvalho Chehab 	buf->vb.field  = field;
980c0d06caSMauro Carvalho Chehab 
990c0d06caSMauro Carvalho Chehab 	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
1000c0d06caSMauro Carvalho Chehab 		rc = videobuf_iolock(q, &buf->vb, NULL);
1010c0d06caSMauro Carvalho Chehab 		if (rc < 0)
1020c0d06caSMauro Carvalho Chehab 			goto fail;
1030c0d06caSMauro Carvalho Chehab 	}
1040c0d06caSMauro Carvalho Chehab 
1050c0d06caSMauro Carvalho Chehab 	buf->vb.state = VIDEOBUF_PREPARED;
1060c0d06caSMauro Carvalho Chehab 	return 0;
1070c0d06caSMauro Carvalho Chehab 
1080c0d06caSMauro Carvalho Chehab fail:
1090c0d06caSMauro Carvalho Chehab 	free_buffer(q, buf);
1100c0d06caSMauro Carvalho Chehab 	return rc;
1110c0d06caSMauro Carvalho Chehab }
1120c0d06caSMauro Carvalho Chehab 
1130c0d06caSMauro Carvalho Chehab static void
1140c0d06caSMauro Carvalho Chehab vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
1150c0d06caSMauro Carvalho Chehab {
1160c0d06caSMauro Carvalho Chehab 	struct au0828_buffer    *buf     = container_of(vb,
1170c0d06caSMauro Carvalho Chehab 							struct au0828_buffer,
1180c0d06caSMauro Carvalho Chehab 							vb);
1190c0d06caSMauro Carvalho Chehab 	struct au0828_fh        *fh      = vq->priv_data;
1200c0d06caSMauro Carvalho Chehab 	struct au0828_dev       *dev     = fh->dev;
1210c0d06caSMauro Carvalho Chehab 	struct au0828_dmaqueue  *vbiq    = &dev->vbiq;
1220c0d06caSMauro Carvalho Chehab 
1230c0d06caSMauro Carvalho Chehab 	buf->vb.state = VIDEOBUF_QUEUED;
1240c0d06caSMauro Carvalho Chehab 	list_add_tail(&buf->vb.queue, &vbiq->active);
1250c0d06caSMauro Carvalho Chehab }
1260c0d06caSMauro Carvalho Chehab 
1270c0d06caSMauro Carvalho Chehab static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
1280c0d06caSMauro Carvalho Chehab {
1290c0d06caSMauro Carvalho Chehab 	struct au0828_buffer *buf = container_of(vb, struct au0828_buffer, vb);
1300c0d06caSMauro Carvalho Chehab 	free_buffer(q, buf);
1310c0d06caSMauro Carvalho Chehab }
1320c0d06caSMauro Carvalho Chehab 
1330c0d06caSMauro Carvalho Chehab struct videobuf_queue_ops au0828_vbi_qops = {
1340c0d06caSMauro Carvalho Chehab 	.buf_setup    = vbi_setup,
1350c0d06caSMauro Carvalho Chehab 	.buf_prepare  = vbi_prepare,
1360c0d06caSMauro Carvalho Chehab 	.buf_queue    = vbi_queue,
1370c0d06caSMauro Carvalho Chehab 	.buf_release  = vbi_release,
1380c0d06caSMauro Carvalho Chehab };
139