* Update VIP to videobuf2 and control framework
@ 2012-07-31 20:17 Federico Vaga
2012-07-31 20:17 ` [PATCH 1/3] [media] adv7180: remove {query/g_/s_}ctrl Federico Vaga
` (4 more replies)
0 siblings, 5 replies; 22+ messages in thread
From: Federico Vaga @ 2012-07-31 20:17 UTC (permalink / raw)
To: Mauro Carvalho Chehab, Pawel Osciak, Marek Szyprowski,
Hans Verkuil
Cc: Giancarlo Asnaghi, linux-media, linux-kernel, Jonathan Corbet
As suggested I moved the Video Buffer Input (VIP) of the STA2X11 board to the
videobuf2. This patch series is an RFC.
The first patch is just an update to the adv7180 because the VIP (the only
user) now use the control framework so query{g_|s_|ctrl} are not necessery.
The second patch adds a new memory allocator for the videobuf2. I name it
videobuf2-dma-streaming but I think "streaming" is not the best choice, so
suggestions are welcome. My inspiration for this buffer come from
videobuf-dma-contig (cached) version. After I made this buffer I found the
videobuf2-dma-nc made by Jonathan Corbet and I improve the allocator with
some suggestions (http://patchwork.linuxtv.org/patch/7441/). The VIP doesn't
work with videobu2-dma-contig and I think this solution is easier the sg.
The third patch updates the VIP to videobuf2 and control framework. I made also
some restyling to the driver and change some mechanism so I take the ownership
of the driver and I add the copyright of ST Microelectronics. Some trivial
code is unchanged. The patch probably needs some extra update.
I add the control framework to the VIP but without any control. I add it to
inherit controls from adv7180.
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 1/3] [media] adv7180: remove {query/g_/s_}ctrl
2012-07-31 20:17 Update VIP to videobuf2 and control framework Federico Vaga
@ 2012-07-31 20:17 ` Federico Vaga
2012-07-31 20:20 ` Federico Vaga
2012-07-31 20:17 ` [PATCH 2/3] [media] videobuf2-dma-streaming: new videobuf2 memory allocator Federico Vaga
` (3 subsequent siblings)
4 siblings, 1 reply; 22+ messages in thread
From: Federico Vaga @ 2012-07-31 20:17 UTC (permalink / raw)
To: Mauro Carvalho Chehab, Pawel Osciak, Marek Szyprowski,
Hans Verkuil
Cc: Giancarlo Asnaghi, linux-media, linux-kernel, Jonathan Corbet,
Federico Vaga
Signed-off-by: Federico Vaga <federico.vaga@gmail.com>
---
drivers/media/video/adv7180.c | 3 ---
1 file modificato, 3 rimozioni(-)
diff --git a/drivers/media/video/adv7180.c b/drivers/media/video/adv7180.c
index 07bb550..bcc7d60 100644
--- a/drivers/media/video/adv7180.c
+++ b/drivers/media/video/adv7180.c
@@ -402,9 +402,6 @@ static const struct v4l2_subdev_video_ops adv7180_video_ops = {
static const struct v4l2_subdev_core_ops adv7180_core_ops = {
.g_chip_ident = adv7180_g_chip_ident,
.s_std = adv7180_s_std,
- .queryctrl = v4l2_subdev_queryctrl,
- .g_ctrl = v4l2_subdev_g_ctrl,
- .s_ctrl = v4l2_subdev_s_ctrl,
};
static const struct v4l2_subdev_ops adv7180_ops = {
--
1.7.11.2
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 2/3] [media] videobuf2-dma-streaming: new videobuf2 memory allocator
2012-07-31 20:17 Update VIP to videobuf2 and control framework Federico Vaga
2012-07-31 20:17 ` [PATCH 1/3] [media] adv7180: remove {query/g_/s_}ctrl Federico Vaga
@ 2012-07-31 20:17 ` Federico Vaga
2012-08-20 8:03 ` Marek Szyprowski
2012-07-31 20:17 ` [PATCH 3/3] [media] sta2x11_vip: convert to videobuf2 and control framework Federico Vaga
` (2 subsequent siblings)
4 siblings, 1 reply; 22+ messages in thread
From: Federico Vaga @ 2012-07-31 20:17 UTC (permalink / raw)
To: Mauro Carvalho Chehab, Pawel Osciak, Marek Szyprowski,
Hans Verkuil
Cc: Giancarlo Asnaghi, linux-media, linux-kernel, Jonathan Corbet,
Federico Vaga
Signed-off-by: Federico Vaga <federico.vaga@gmail.com>
---
drivers/media/video/Kconfig | 6 +-
drivers/media/video/Makefile | 1 +
drivers/media/video/videobuf2-dma-streaming.c | 187 ++++++++++++++++++++++++++
include/media/videobuf2-dma-streaming.h | 24 ++++
4 file modificati, 217 inserzioni(+). 1 rimozione(-)
create mode 100644 drivers/media/video/videobuf2-dma-streaming.c
create mode 100644 include/media/videobuf2-dma-streaming.h
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index be6d718..6c60b59 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -59,6 +59,10 @@ config VIDEOBUF2_DMA_NC
select VIDEOBUF2_CORE
select VIDEOBUF2_MEMOPS
tristate
+config VIDEOBUF2_DMA_STREAMING
+ select VIDEOBUF2_CORE
+ select VIDEOBUF2_MEMOPS
+ tristate
config VIDEOBUF2_VMALLOC
select VIDEOBUF2_CORE
@@ -844,7 +848,7 @@ config STA2X11_VIP
tristate "STA2X11 VIP Video For Linux"
depends on STA2X11
select VIDEO_ADV7180 if VIDEO_HELPER_CHIPS_AUTO
- select VIDEOBUF_DMA_CONTIG
+ select VIDEOBUF2_DMA_STREAMING
depends on PCI && VIDEO_V4L2 && VIRT_TO_BUS
help
Say Y for support for STA2X11 VIP (Video Input Port) capture
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 30234af..c1a08b9e 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -140,6 +140,7 @@ obj-$(CONFIG_VIDEOBUF2_VMALLOC) += videobuf2-vmalloc.o
obj-$(CONFIG_VIDEOBUF2_DMA_CONTIG) += videobuf2-dma-contig.o
obj-$(CONFIG_VIDEOBUF2_DMA_SG) += videobuf2-dma-sg.o
obj-$(CONFIG_VIDEOBUF2_DMA_NC) += videobuf2-dma-nc.o
+obj-$(CONFIG_VIDEOBUF2_DMA_STREAMING) += videobuf2-dma-streaming.o
obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o
diff --git a/drivers/media/video/videobuf2-dma-streaming.c b/drivers/media/video/videobuf2-dma-streaming.c
new file mode 100644
index 0000000..d96d3d9
--- /dev/null
+++ b/drivers/media/video/videobuf2-dma-streaming.c
@@ -0,0 +1,187 @@
+/*
+ * videobuf2-dma-streaming.c - DMA streaming memory allocator for videobuf2
+ *
+ * Copyright (C) 2012 Federico Vaga <federico.vaga@gmail.com>
+ * *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/pagemap.h>
+#include <linux/dma-mapping.h>
+
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-streaming.h>
+#include <media/videobuf2-memops.h>
+
+struct vb2_streaming_conf {
+ struct device *dev;
+};
+struct vb2_streaming_buf {
+ struct vb2_streaming_conf *conf;
+ void *vaddr;
+
+ dma_addr_t dma_handle;
+
+ unsigned long size;
+ struct vm_area_struct *vma;
+
+ atomic_t refcount;
+ struct vb2_vmarea_handler handler;
+};
+
+static void vb2_dma_streaming_put(void *buf_priv)
+{
+ struct vb2_streaming_buf *buf = buf_priv;
+
+ if (atomic_dec_and_test(&buf->refcount)) {
+ dma_unmap_single(buf->conf->dev, buf->dma_handle, buf->size,
+ DMA_FROM_DEVICE);
+ free_pages_exact(buf->vaddr, buf->size);
+ kfree(buf);
+ }
+
+}
+
+static void *vb2_dma_streaming_alloc(void *alloc_ctx, unsigned long size)
+{
+ struct vb2_streaming_conf *conf = alloc_ctx;
+ struct vb2_streaming_buf *buf;
+ int err;
+
+ buf = kzalloc(sizeof *buf, GFP_KERNEL);
+ if (!buf)
+ return ERR_PTR(-ENOMEM);
+ buf->vaddr = alloc_pages_exact(size, GFP_KERNEL | GFP_DMA);
+ if (!buf->vaddr) {
+ err = -ENOMEM;
+ goto out;
+ }
+ buf->dma_handle = dma_map_single(conf->dev, buf->vaddr, size,
+ DMA_FROM_DEVICE);
+ err = dma_mapping_error(conf->dev, buf->dma_handle);
+ if (err) {
+ dev_err(conf->dev, "dma_map_single failed\n");
+
+ free_pages_exact(buf->vaddr, size);
+ buf->vaddr = NULL;
+ goto out_pages;
+ }
+ buf->conf = conf;
+ buf->size = size;
+ buf->handler.refcount = &buf->refcount;
+ buf->handler.put = vb2_dma_streaming_put;
+ buf->handler.arg = buf;
+
+ atomic_inc(&buf->refcount);
+ return buf;
+
+out_pages:
+ free_pages_exact(buf->vaddr, buf->size);
+out:
+ kfree(buf);
+ return ERR_PTR(err);
+}
+
+static void *vb2_dma_streaming_cookie(void *buf_priv)
+{
+ struct vb2_streaming_buf *buf = buf_priv;
+
+ return (void *)buf->dma_handle;
+}
+
+static void *vb2_dma_streaming_vaddr(void *buf_priv)
+{
+ struct vb2_streaming_buf *buf = buf_priv;
+
+ if (!buf)
+ return NULL;
+ return buf->vaddr;
+}
+
+static unsigned int vb2_dma_streaming_num_users(void *buf_priv)
+{
+ struct vb2_streaming_buf *buf = buf_priv;
+
+ return atomic_read(&buf->refcount);
+}
+
+static int vb2_dma_streaming_mmap(void *buf_priv, struct vm_area_struct *vma)
+{
+ struct vb2_streaming_buf *buf = buf_priv;
+ unsigned long pos, start = vma->vm_start;
+ unsigned long size;
+ struct page *page;
+ int err;
+
+ /* Try to remap memory */
+ size = vma->vm_end - vma->vm_start;
+ size = (size < buf->size) ? size : buf->size;
+ pos = (unsigned long)buf->vaddr;
+
+ while (size > 0) {
+ page = virt_to_page((void *)pos);
+ if (!page) {
+ dev_err(buf->conf->dev, "mmap: virt_to_page failed\n");
+ return -ENOMEM;
+ }
+ err = vm_insert_page(vma, start, page);
+ if (err) {
+ dev_err(buf->conf->dev, "mmap: insert failed %d\n", err);
+ return -ENOMEM;
+ }
+ start += PAGE_SIZE;
+ pos += PAGE_SIZE;
+
+ if (size > PAGE_SIZE)
+ size -= PAGE_SIZE;
+ else
+ size = 0;
+ }
+
+
+ vma->vm_ops = &vb2_common_vm_ops;
+ vma->vm_flags |= VM_DONTEXPAND;
+ vma->vm_private_data = &buf->handler;
+
+ vma->vm_ops->open(vma);
+
+ return 0;
+}
+
+const struct vb2_mem_ops vb2_dma_streaming_memops = {
+ .alloc = vb2_dma_streaming_alloc,
+ .put = vb2_dma_streaming_put,
+ .cookie = vb2_dma_streaming_cookie,
+ .vaddr = vb2_dma_streaming_vaddr,
+ .mmap = vb2_dma_streaming_mmap,
+ .num_users = vb2_dma_streaming_num_users,
+};
+EXPORT_SYMBOL_GPL(vb2_dma_streaming_memops);
+
+void *vb2_dma_streaming_init_ctx(struct device *dev)
+{
+ struct vb2_streaming_conf *conf;
+
+ conf = kmalloc(sizeof *conf, GFP_KERNEL);
+ if (!conf)
+ return ERR_PTR(-ENOMEM);
+
+ conf->dev = dev;
+
+ return conf;
+}
+EXPORT_SYMBOL_GPL(vb2_dma_streaming_init_ctx);
+
+void vb2_dma_streaming_cleanup_ctx(void *alloc_ctx)
+{
+ kfree(alloc_ctx);
+}
+EXPORT_SYMBOL_GPL(vb2_dma_streaming_cleanup_ctx);
+
+MODULE_DESCRIPTION("DMA-streaming memory allocator for videobuf2");
+MODULE_AUTHOR("Federico Vaga <federico.vaga@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/include/media/videobuf2-dma-streaming.h b/include/media/videobuf2-dma-streaming.h
new file mode 100644
index 0000000..89cbd06
--- /dev/null
+++ b/include/media/videobuf2-dma-streaming.h
@@ -0,0 +1,24 @@
+/*
+ * videobuf2-dma-streaming.h - DMA steaming memory allocator for videobuf2
+ *
+ * Copyright (C) 2012 Federico Vaga
+ *
+ * Author: Federico Vaga <federico.vaga@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ */
+
+#ifndef _MEDIA_VIDEOBUF2_DMA_STREAMING_H
+#define _MEDIA_VIDEOBUF2_DMA_STREAMING_H
+
+#include <media/videobuf2-core.h>
+#include <linux/dma-mapping.h>
+
+void *vb2_dma_streaming_init_ctx(struct device *dev);
+void vb2_dma_streaming_cleanup_ctx(void *alloc_ctx);
+
+extern const struct vb2_mem_ops vb2_dma_streaming_memops;
+
+#endif
--
1.7.11.2
^ permalink raw reply related [flat|nested] 22+ messages in thread
* [PATCH 3/3] [media] sta2x11_vip: convert to videobuf2 and control framework
2012-07-31 20:17 Update VIP to videobuf2 and control framework Federico Vaga
2012-07-31 20:17 ` [PATCH 1/3] [media] adv7180: remove {query/g_/s_}ctrl Federico Vaga
2012-07-31 20:17 ` [PATCH 2/3] [media] videobuf2-dma-streaming: new videobuf2 memory allocator Federico Vaga
@ 2012-07-31 20:17 ` Federico Vaga
2012-08-06 8:17 ` [PATCH 3/3 v2] " Federico Vaga
2012-07-31 20:27 ` Update VIP " Federico Vaga
2012-08-01 6:41 ` Hans Verkuil
4 siblings, 1 reply; 22+ messages in thread
From: Federico Vaga @ 2012-07-31 20:17 UTC (permalink / raw)
To: Mauro Carvalho Chehab, Pawel Osciak, Marek Szyprowski,
Hans Verkuil
Cc: Giancarlo Asnaghi, linux-media, linux-kernel, Jonathan Corbet,
Federico Vaga
Signed-off-by: Federico Vaga <federico.vaga@gmail.com>
Acked-by: Giancarlo Asnaghi <giancarlo.asnaghi@st.com>
---
drivers/media/video/sta2x11_vip.c | 1134 ++++++++++++++-----------------------
1 file modificato, 410 inserzioni(+), 724 rimozioni(-)
diff --git a/drivers/media/video/sta2x11_vip.c b/drivers/media/video/sta2x11_vip.c
index 4c10205..5a75718 100644
--- a/drivers/media/video/sta2x11_vip.c
+++ b/drivers/media/video/sta2x11_vip.c
@@ -1,6 +1,7 @@
/*
* This is the driver for the STA2x11 Video Input Port.
*
+ * Copyright (C) 2012 ST Microelectronics
* Copyright (C) 2010 WindRiver Systems, Inc.
*
* This program is free software; you can redistribute it and/or modify it
@@ -19,36 +20,28 @@
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
- * Author: Andreas Kies <andreas.kies@windriver.com>
- * Vlad Lungu <vlad.lungu@windriver.com>
- *
*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/vmalloc.h>
-
#include <linux/videodev2.h>
-
#include <linux/kmod.h>
-
#include <linux/pci.h>
#include <linux/interrupt.h>
-#include <linux/mutex.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
#include <media/v4l2-ioctl.h>
-#include <media/videobuf-dma-contig.h>
+#include <media/videobuf2-dma-streaming.h>
#include "sta2x11_vip.h"
-#define DRV_NAME "sta2x11_vip"
#define DRV_VERSION "1.3"
#ifndef PCI_DEVICE_ID_STMICRO_VIP
@@ -63,8 +56,8 @@
#define DVP_TFS 0x08
#define DVP_BFO 0x0C
#define DVP_BFS 0x10
-#define DVP_VTP 0x14
-#define DVP_VBP 0x18
+#define DVP_VTP 0x14
+#define DVP_VBP 0x18
#define DVP_VMP 0x1C
#define DVP_ITM 0x98
#define DVP_ITS 0x9C
@@ -84,43 +77,20 @@
#define DVP_HLFLN_SD 0x00000001
-#define REG_WRITE(vip, reg, value) iowrite32((value), (vip->iomem)+(reg))
-#define REG_READ(vip, reg) ioread32((vip->iomem)+(reg))
-
#define SAVE_COUNT 8
#define AUX_COUNT 3
#define IRQ_COUNT 1
-/**
- * struct sta2x11_vip - All internal data for one instance of device
- * @v4l2_dev: device registered in v4l layer
- * @video_dev: properties of our device
- * @pdev: PCI device
- * @adapter: contains I2C adapter information
- * @register_save_area: All relevant register are saved here during suspend
- * @decoder: contains information about video DAC
- * @format: pixel format, fixed UYVY
- * @std: video standard (e.g. PAL/NTSC)
- * @input: input line for video signal ( 0 or 1 )
- * @users: Number of open of device ( max. 1 )
- * @disabled: Device is in power down state
- * @mutex: ensures exclusive opening of device
- * @slock: for excluse acces of registers
- * @vb_vidq: queue maintained by videobuf layer
- * @capture: linked list of capture buffer
- * @active: struct videobuf_buffer currently beingg filled
- * @started: device is ready to capture frame
- * @closing: device will be shut down
- * @tcount: Number of top frames
- * @bcount: Number of bottom frames
- * @overflow: Number of FIFO overflows
- * @mem_spare: small buffer of unused frame
- * @dma_spare: dma addres of mem_spare
- * @iomem: hardware base address
- * @config: I2C and gpio config from platform
- *
- * All non-local data is accessed via this structure.
- */
+
+struct vip_buffer {
+ struct vb2_buffer vb;
+ struct list_head list;
+ dma_addr_t dma;
+};
+static inline struct vip_buffer *to_vip_buffer(struct vb2_buffer *vb2)
+{
+ return container_of(vb2, struct vip_buffer, vb);
+}
struct sta2x11_vip {
struct v4l2_device v4l2_dev;
@@ -129,21 +99,28 @@ struct sta2x11_vip {
struct i2c_adapter *adapter;
unsigned int register_save_area[IRQ_COUNT + SAVE_COUNT + AUX_COUNT];
struct v4l2_subdev *decoder;
- struct v4l2_pix_format format;
- v4l2_std_id std;
- unsigned int input;
- int users;
- int disabled;
- struct mutex mutex; /* exclusive access during open */
- spinlock_t slock; /* spin lock for hardware and queue access */
- struct videobuf_queue vb_vidq;
- struct list_head capture;
- struct videobuf_buffer *active;
- int started, closing, tcount, bcount;
+ struct v4l2_ctrl_handler ctrl_hdl;
+
+
+ struct v4l2_pix_format format; /* pixel format, fixed UYVY */
+ v4l2_std_id std; /* Video standard (PAL/NTSC)*/
+ unsigned int input; /* Input line (0 or 1) */
+ int disabled; /* 1 disabled 0 enabled */
+ spinlock_t slock; /* spin lock for hardware */
+
+ struct vb2_alloc_ctx *alloc_ctx;
+ struct vb2_queue vb_vidq; /* queue maintaned by videobuf2 */
+ struct list_head buffer_list; /* list of buffers */
+ unsigned int sequence;
+ struct vip_buffer *active; /* current active buffer */
+ spinlock_t lock; /* Used in videobuf2 callback */
+
+ unsigned int closing; /* 1 if VIP is closing*/
+ /* Interrupt counters */
+ int tcount, bcount;
int overflow;
- void *mem_spare;
- dma_addr_t dma_spare;
- void *iomem;
+
+ void *iomem; /* I/O Memory */
struct vip_config *config;
};
@@ -206,324 +183,281 @@ static struct v4l2_pix_format formats_60[] = {
.colorspace = V4L2_COLORSPACE_SMPTE170M},
};
-/**
- * buf_setup - Get size and number of video buffer
- * @vq: queue in videobuf
- * @count: Number of buffers (1..MAX_FRAMES).
- * 0 use default value.
- * @size: size of buffer in bytes
- *
- * returns size and number of buffers
- * a preset value of 0 returns the default number.
- * return value: 0, always succesfull.
- */
-static int buf_setup(struct videobuf_queue *vq, unsigned int *count,
- unsigned int *size)
+/* Write VIP register */
+static inline void reg_write(struct sta2x11_vip *vip, unsigned int reg, u32 val)
+{
+ iowrite32((val), (vip->iomem)+(reg));
+}
+/* Read VIP register */
+static inline u32 reg_read(struct sta2x11_vip *vip, unsigned int reg)
{
- struct sta2x11_vip *vip = vq->priv_data;
+ return ioread32((vip->iomem)+(reg));
+}
+/* Start DMA acquisition */
+static void start_dma(struct sta2x11_vip *vip, struct vip_buffer *vip_buf)
+{
+ unsigned long offset = 0;
- *size = vip->format.width * vip->format.height * 2;
- if (0 == *count || MAX_FRAMES < *count)
- *count = MAX_FRAMES;
- return 0;
-};
+ if (vip->format.field == V4L2_FIELD_INTERLACED)
+ offset = vip->format.width * 2;
-/**
- * buf_prepare - prepare buffer for usage
- * @vq: queue in videobuf layer
- * @vb: buffer to be prepared
- * @field: type of video data (interlaced/non-interlaced)
- *
- * Allocate or realloc buffer
- * return value: 0, successful.
- *
- * -EINVAL, supplied buffer is too small.
- *
- * other, buffer could not be locked.
- */
-static int buf_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
- enum v4l2_field field)
-{
- struct sta2x11_vip *vip = vq->priv_data;
- int ret;
+ spin_lock_irq(&vip->slock);
+ /* Enable acquisition */
+ reg_write(vip, DVP_CTL, reg_read(vip, DVP_CTL) | DVP_CTL_ENA);
+ /* Set Top and Bottom Field memory address */
+ reg_write(vip, DVP_VTP, (u32)vip_buf->dma);
+ reg_write(vip, DVP_VBP, (u32)vip_buf->dma + offset);
+ spin_unlock_irq(&vip->slock);
+}
- vb->size = vip->format.width * vip->format.height * 2;
- if ((0 != vb->baddr) && (vb->bsize < vb->size))
- return -EINVAL;
- vb->width = vip->format.width;
- vb->height = vip->format.height;
- vb->field = field;
-
- if (VIDEOBUF_NEEDS_INIT == vb->state) {
- ret = videobuf_iolock(vq, vb, NULL);
- if (ret)
- goto fail;
+/* Fetch the next buffer to activate */
+static void vip_active_buf_next(struct sta2x11_vip *vip)
+{
+ /* Get the next buffer */
+ spin_lock(&vip->lock);
+ if (list_empty(&vip->buffer_list)) {/* No available buffer */
+ spin_unlock(&vip->lock);
+ return;
+ }
+ vip->active = list_first_entry(&vip->buffer_list,
+ struct vip_buffer,
+ list);
+ /* Reset Top and Bottom counter */
+ vip->tcount = 0;
+ vip->bcount = 0;
+ spin_unlock(&vip->lock);
+ if (vb2_is_streaming(&vip->vb_vidq)) { /* streaming is on */
+ start_dma(vip, vip->active); /* start dma capture */
}
- vb->state = VIDEOBUF_PREPARED;
- return 0;
-fail:
- videobuf_dma_contig_free(vq, vb);
- vb->state = VIDEOBUF_NEEDS_INIT;
- return ret;
}
-/**
- * buf_queu - queue buffer for filling
- * @vq: queue in videobuf layer
- * @vb: buffer to be queued
- *
- * if capturing is already running, the buffer will be queued. Otherwise
- * capture is started and the buffer is used directly.
- */
-static void buf_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+
+/* Videobuf2 Operations */
+static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], void *alloc_ctxs[])
{
- struct sta2x11_vip *vip = vq->priv_data;
- u32 dma;
+ struct sta2x11_vip *vip = vb2_get_drv_priv(vq);
- vb->state = VIDEOBUF_QUEUED;
+ if (!(*nbuffers) || *nbuffers < MAX_FRAMES)
+ *nbuffers = MAX_FRAMES;
- if (vip->active) {
- list_add_tail(&vb->queue, &vip->capture);
- return;
- }
+ *nplanes = 1;
+ sizes[0] = vip->format.sizeimage;
+ alloc_ctxs[0] = vip->alloc_ctx;
- vip->started = 1;
+ vip->sequence = 0;
+ vip->active = NULL;
vip->tcount = 0;
vip->bcount = 0;
- vip->active = vb;
- vb->state = VIDEOBUF_ACTIVE;
- dma = videobuf_to_dma_contig(vb);
+ return 0;
+};
+static int buffer_init(struct vb2_buffer *vb)
+{
+ struct vip_buffer *vip_buf = to_vip_buffer(vb);
- REG_WRITE(vip, DVP_TFO, (0 << 16) | (0));
- /* despite of interlace mode, upper and lower frames start at zero */
- REG_WRITE(vip, DVP_BFO, (0 << 16) | (0));
+ vip_buf->dma = (dma_addr_t)vb2_plane_cookie(vb, 0);
+ INIT_LIST_HEAD(&vip_buf->list);
+ return 0;
+}
- switch (vip->format.field) {
- case V4L2_FIELD_INTERLACED:
- REG_WRITE(vip, DVP_TFS,
- ((vip->format.height / 2 - 1) << 16) |
- (2 * vip->format.width - 1));
- REG_WRITE(vip, DVP_BFS, ((vip->format.height / 2 - 1) << 16) |
- (2 * vip->format.width - 1));
- REG_WRITE(vip, DVP_VTP, dma);
- REG_WRITE(vip, DVP_VBP, dma + vip->format.width * 2);
- REG_WRITE(vip, DVP_VMP, 4 * vip->format.width);
- break;
- case V4L2_FIELD_TOP:
- REG_WRITE(vip, DVP_TFS,
- ((vip->format.height - 1) << 16) |
- (2 * vip->format.width - 1));
- REG_WRITE(vip, DVP_BFS, ((0) << 16) |
- (2 * vip->format.width - 1));
- REG_WRITE(vip, DVP_VTP, dma);
- REG_WRITE(vip, DVP_VBP, dma);
- REG_WRITE(vip, DVP_VMP, 2 * vip->format.width);
- break;
- case V4L2_FIELD_BOTTOM:
- REG_WRITE(vip, DVP_TFS, ((0) << 16) |
- (2 * vip->format.width - 1));
- REG_WRITE(vip, DVP_BFS,
- ((vip->format.height) << 16) |
- (2 * vip->format.width - 1));
- REG_WRITE(vip, DVP_VTP, dma);
- REG_WRITE(vip, DVP_VBP, dma);
- REG_WRITE(vip, DVP_VMP, 2 * vip->format.width);
- break;
+static int buffer_prepare(struct vb2_buffer *vb)
+{
+ struct sta2x11_vip *vip = vb2_get_drv_priv(vb->vb2_queue);
+ struct vip_buffer *vip_buf = to_vip_buffer(vb);
+ unsigned long size;
+
+ size = vip->format.sizeimage;
+ if (vb2_plane_size(vb, 0) < size) {
+ v4l2_err(&vip->v4l2_dev, "buffer too small (%lu < %lu)\n",
+ vb2_plane_size(vb, 0), size);
+ return -EINVAL;
+ }
- default:
- pr_warning("VIP: unknown field format\n");
- return;
+ vb2_set_plane_payload(&vip_buf->vb, 0, size);
+
+ return 0;
+}
+static void buffer_queue(struct vb2_buffer *vb)
+{
+ struct sta2x11_vip *vip = vb2_get_drv_priv(vb->vb2_queue);
+ struct vip_buffer *vip_buf = to_vip_buffer(vb);
+ unsigned long size;
+
+ size = vip->format.sizeimage;
+ dma_sync_single_for_device(&vip->pdev->dev, vip_buf->dma,
+ size, DMA_FROM_DEVICE);
+ spin_lock(&vip->lock);
+ list_add_tail(&vip_buf->list, &vip->buffer_list);
+ if (!vip->active) { /* No active buffer, active the first one */
+ vip->active = list_first_entry(&vip->buffer_list,
+ struct vip_buffer,
+ list);
+ if (vb2_is_streaming(&vip->vb_vidq)) /* streaming is on */
+ start_dma(vip, vip_buf); /* start dma capture */
}
+ spin_unlock(&vip->lock);
+}
+static int buffer_finish(struct vb2_buffer *vb)
+{
+ struct sta2x11_vip *vip = vb2_get_drv_priv(vb->vb2_queue);
+ struct vip_buffer *vip_buf = to_vip_buffer(vb);
+ unsigned long size;
+
+ /* Buffer handled, remove it from the list */
+ spin_lock(&vip->lock);
+ list_del_init(&vip_buf->list);
+ spin_unlock(&vip->lock);
+ /* DMA sync */
+ size = vip->format.sizeimage;
+ dma_sync_single_for_cpu(&vip->pdev->dev, vip_buf->dma,
+ size, DMA_FROM_DEVICE);
+
+ vip_active_buf_next(vip);
- REG_WRITE(vip, DVP_CTL, DVP_CTL_ENA);
+ return 0;
}
-/**
- * buff_release - release buffer
- * @vq: queue in videobuf layer
- * @vb: buffer to be released
- *
- * release buffer in videobuf layer
- */
-static void buf_release(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+static int start_streaming(struct vb2_queue *vq, unsigned int count)
{
+ struct sta2x11_vip *vip = vb2_get_drv_priv(vq);
+
+ /* Enable interrupt VSYNC Top and Bottom*/
+ reg_write(vip, DVP_ITM, DVP_IT_VSB | DVP_IT_VST);
- videobuf_dma_contig_free(vq, vb);
- vb->state = VIDEOBUF_NEEDS_INIT;
+ if (count)
+ start_dma(vip, vip->active);
+
+ return 0;
}
-static struct videobuf_queue_ops vip_qops = {
- .buf_setup = buf_setup,
- .buf_prepare = buf_prepare,
- .buf_queue = buf_queue,
- .buf_release = buf_release,
+/* abort streaming and wait for last buffer */
+static int stop_streaming(struct vb2_queue *vq)
+{
+ struct sta2x11_vip *vip = vb2_get_drv_priv(vq);
+ struct vip_buffer *vip_buf, *node;
+
+ /* Disable acquisition */
+ reg_write(vip, DVP_CTL, reg_read(vip, DVP_CTL) & ~DVP_CTL_ENA);
+ /* Disable all interrupts */
+ reg_write(vip, DVP_ITM, 0);
+
+ /* Release all active buffers */
+ spin_lock(&vip->lock);
+ list_for_each_entry_safe(vip_buf, node, &vip->buffer_list, list) {
+ vb2_buffer_done(&vip_buf->vb, VB2_BUF_STATE_ERROR);
+ }
+ spin_unlock(&vip->lock);
+
+ return 0;
+}
+
+static struct vb2_ops vip_video_qops = {
+ .queue_setup = queue_setup,
+ .buf_init = buffer_init,
+ .buf_prepare = buffer_prepare,
+ .buf_finish = buffer_finish,
+ .buf_queue = buffer_queue,
+ .start_streaming = start_streaming,
+ .stop_streaming = stop_streaming,
};
-/**
- * vip_open - open video device
- * @file: descriptor of device
- *
- * open device, make sure it is only opened once.
- * return value: 0, no error.
- *
- * -EBUSY, device is already opened
- *
- * -ENOMEM, no memory for auxiliary DMA buffer
- */
+
+/* File Operations */
static int vip_open(struct file *file)
{
struct video_device *dev = video_devdata(file);
struct sta2x11_vip *vip = video_get_drvdata(dev);
-
- mutex_lock(&vip->mutex);
- vip->users++;
-
- if (vip->users > 1) {
- vip->users--;
- mutex_unlock(&vip->mutex);
- return -EBUSY;
- }
+ int err;
file->private_data = dev;
vip->overflow = 0;
- vip->started = 0;
vip->closing = 0;
vip->active = NULL;
- INIT_LIST_HEAD(&vip->capture);
- vip->mem_spare = dma_alloc_coherent(&vip->pdev->dev, 64,
- &vip->dma_spare, GFP_KERNEL);
- if (!vip->mem_spare) {
- vip->users--;
- mutex_unlock(&vip->mutex);
- return -ENOMEM;
+ INIT_LIST_HEAD(&vip->buffer_list);
+ vip->alloc_ctx = vb2_dma_streaming_init_ctx(&vip->pdev->dev);
+ if (IS_ERR(vip->alloc_ctx)) {
+ v4l2_err(&vip->v4l2_dev, "Can't allocate buffer context");
+ err = PTR_ERR(vip->alloc_ctx);
+ return PTR_ERR(vip->alloc_ctx);
}
+ spin_lock_irq(&vip->slock);
+ /* Clean interrupt */
+ reg_read(vip, DVP_ITS);
+ /* Enable Half Line per vertical */
+ reg_write(vip, DVP_HLFLN, DVP_HLFLN_SD);
+ /* Reset VIP control */
+ reg_write(vip, DVP_CTL, DVP_CTL_RST);
+ /* Clear VIP control */
+ reg_write(vip, DVP_CTL, 0);
+ spin_unlock_irq(&vip->slock);
- mutex_unlock(&vip->mutex);
- videobuf_queue_dma_contig_init_cached(&vip->vb_vidq,
- &vip_qops,
- &vip->pdev->dev,
- &vip->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_INTERLACED,
- sizeof(struct videobuf_buffer),
- vip, NULL);
- REG_READ(vip, DVP_ITS);
- REG_WRITE(vip, DVP_HLFLN, DVP_HLFLN_SD);
- REG_WRITE(vip, DVP_ITM, DVP_IT_VSB | DVP_IT_VST);
- REG_WRITE(vip, DVP_CTL, DVP_CTL_RST);
- REG_WRITE(vip, DVP_CTL, 0);
- REG_READ(vip, DVP_ITS);
return 0;
}
-
-/**
- * vip_close - close video device
- * @file: descriptor of device
- *
- * close video device, wait until all pending operations are finished
- * ( maximum FRAME_MAX buffers pending )
- * Turn off interrupts.
- *
- * return value: 0, always succesful.
- */
static int vip_close(struct file *file)
{
struct video_device *dev = video_devdata(file);
struct sta2x11_vip *vip = video_get_drvdata(dev);
vip->closing = 1;
- if (vip->active)
- videobuf_waiton(&vip->vb_vidq, vip->active, 0, 0);
- spin_lock_irq(&vip->slock);
-
- REG_WRITE(vip, DVP_ITM, 0);
- REG_WRITE(vip, DVP_CTL, DVP_CTL_RST);
- REG_WRITE(vip, DVP_CTL, 0);
- REG_READ(vip, DVP_ITS);
- vip->started = 0;
+ spin_lock_irq(&vip->slock);
+ /* Disable interrupt */
+ reg_write(vip, DVP_ITM, 0);
+ /* Reset VIP Control */
+ reg_write(vip, DVP_CTL, DVP_CTL_RST);
+ /* Clear VIP Control */
+ reg_write(vip, DVP_CTL, 0);
+ /* Clean VIP Interrupt */
+ reg_read(vip, DVP_ITS);
+ /* No active buffer*/
vip->active = NULL;
-
spin_unlock_irq(&vip->slock);
- videobuf_stop(&vip->vb_vidq);
- videobuf_mmap_free(&vip->vb_vidq);
+ vb2_dma_streaming_cleanup_ctx(vip->alloc_ctx);
- dma_free_coherent(&vip->pdev->dev, 64, vip->mem_spare, vip->dma_spare);
file->private_data = NULL;
- mutex_lock(&vip->mutex);
- vip->users--;
- mutex_unlock(&vip->mutex);
+
return 0;
}
-
-/**
- * vip_read - read from video input
- * @file: descriptor of device
- * @data: user buffer
- * @count: number of bytes to be read
- * @ppos: position within stream
- *
- * read video data from video device.
- * handling is done in generic videobuf layer
- * return value: provided by videobuf layer
- */
-static ssize_t vip_read(struct file *file, char __user *data,
- size_t count, loff_t *ppos)
+static ssize_t vip_read(struct file *file, char __user *data, size_t count,
+ loff_t *ppos)
{
struct video_device *dev = file->private_data;
struct sta2x11_vip *vip = video_get_drvdata(dev);
- return videobuf_read_stream(&vip->vb_vidq, data, count, ppos, 0,
- file->f_flags & O_NONBLOCK);
+ return vb2_read(&vip->vb_vidq, data, count, ppos,
+ file->f_flags & O_NONBLOCK);
}
-
-/**
- * vip_mmap - map user buffer
- * @file: descriptor of device
- * @vma: user buffer
- *
- * map user space buffer into kernel mode, including DMA address.
- * handling is done in generic videobuf layer.
- * return value: provided by videobuf layer
- */
static int vip_mmap(struct file *file, struct vm_area_struct *vma)
{
struct video_device *dev = file->private_data;
struct sta2x11_vip *vip = video_get_drvdata(dev);
- return videobuf_mmap_mapper(&vip->vb_vidq, vma);
+ return vb2_mmap(&vip->vb_vidq, vma);
}
-
-/**
- * vip_poll - poll for event
- * @file: descriptor of device
- * @wait: contains events to be waited for
- *
- * wait for event related to video device.
- * handling is done in generic videobuf layer.
- * return value: provided by videobuf layer
- */
static unsigned int vip_poll(struct file *file, struct poll_table_struct *wait)
{
struct video_device *dev = file->private_data;
struct sta2x11_vip *vip = video_get_drvdata(dev);
- return videobuf_poll_stream(file, &vip->vb_vidq, wait);
+ return vb2_poll(&vip->vb_vidq, file, wait);
}
-/**
- * vidioc_querycap - return capabilities of device
- * @file: descriptor of device (not used)
- * @priv: points to current videodevice
- * @cap: contains return values
- *
- * the capabilities of the device are returned
- *
- * return value: 0, no error.
- */
+static const struct v4l2_file_operations vip_fops = {
+ .owner = THIS_MODULE,
+ .open = vip_open,
+ .release = vip_close,
+ .unlocked_ioctl = video_ioctl2,
+ .read = vip_read,
+ .mmap = vip_mmap,
+ .poll = vip_poll
+};
+
+
+/* V4L2 ioctl Operations */
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
@@ -531,31 +465,17 @@ static int vidioc_querycap(struct file *file, void *priv,
struct sta2x11_vip *vip = video_get_drvdata(dev);
memset(cap, 0, sizeof(struct v4l2_capability));
- strcpy(cap->driver, DRV_NAME);
- strcpy(cap->card, DRV_NAME);
- cap->version = 0;
+ strcpy(cap->driver, KBUILD_MODNAME);
+ strcpy(cap->card, KBUILD_MODNAME);
snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
pci_name(vip->pdev));
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING;
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
-/**
- * vidioc_s_std - set video standard
- * @file: descriptor of device (not used)
- * @priv: points to current videodevice
- * @std: contains standard to be set
- *
- * the video standard is set
- *
- * return value: 0, no error.
- *
- * -EIO, no input signal detected
- *
- * other, returned from video DAC.
- */
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *std)
{
struct video_device *dev = priv;
@@ -590,16 +510,6 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *std)
return v4l2_subdev_call(vip->decoder, core, s_std, *std);
}
-/**
- * vidioc_g_std - get video standard
- * @file: descriptor of device (not used)
- * @priv: points to current videodevice
- * @std: contains return values
- *
- * the current video standard is returned
- *
- * return value: 0, no error.
- */
static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std)
{
struct video_device *dev = priv;
@@ -609,16 +519,6 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std)
return 0;
}
-/**
- * vidioc_querystd - get possible video standards
- * @file: descriptor of device (not used)
- * @priv: points to current videodevice
- * @std: contains return values
- *
- * all possible video standards are returned
- *
- * return value: delivered by video DAC routine.
- */
static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *std)
{
struct video_device *dev = priv;
@@ -628,72 +528,6 @@ static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *std)
}
-/**
- * vidioc_queryctl - get possible control settings
- * @file: descriptor of device (not used)
- * @priv: points to current videodevice
- * @ctrl: contains return values
- *
- * return possible values for a control
- * return value: delivered by video DAC routine.
- */
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *ctrl)
-{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
-
- return v4l2_subdev_call(vip->decoder, core, queryctrl, ctrl);
-}
-
-/**
- * vidioc_g_ctl - get control value
- * @file: descriptor of device (not used)
- * @priv: points to current videodevice
- * @ctrl: contains return values
- *
- * return setting for a control value
- * return value: delivered by video DAC routine.
- */
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
-
- return v4l2_subdev_call(vip->decoder, core, g_ctrl, ctrl);
-}
-
-/**
- * vidioc_s_ctl - set control value
- * @file: descriptor of device (not used)
- * @priv: points to current videodevice
- * @ctrl: contains value to be set
- *
- * set value for a specific control
- * return value: delivered by video DAC routine.
- */
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
-
- return v4l2_subdev_call(vip->decoder, core, s_ctrl, ctrl);
-}
-
-/**
- * vidioc_enum_input - return name of input line
- * @file: descriptor of device (not used)
- * @priv: points to current videodevice
- * @inp: contains return values
- *
- * the user friendly name of the input line is returned
- *
- * return value: 0, no error.
- *
- * -EINVAL, input line number out of range
- */
static int vidioc_enum_input(struct file *file, void *priv,
struct v4l2_input *inp)
{
@@ -707,18 +541,6 @@ static int vidioc_enum_input(struct file *file, void *priv,
return 0;
}
-/**
- * vidioc_s_input - set input line
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
- * @i: new input line number
- *
- * the current active input line is set
- *
- * return value: 0, no error.
- *
- * -EINVAL, line number out of range
- */
static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
{
struct video_device *dev = priv;
@@ -735,16 +557,6 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
return 0;
}
-/**
- * vidioc_g_input - return input line
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
- * @i: returned input line number
- *
- * the current active input line is returned
- *
- * return value: always 0.
- */
static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
{
struct video_device *dev = priv;
@@ -754,17 +566,6 @@ static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
return 0;
}
-/**
- * vidioc_enum_fmt_vid_cap - return video capture format
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
- * @f: returned format information
- *
- * returns name and format of video capture
- * Only UYVY is supported by hardware.
- *
- * return value: always 0.
- */
static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
@@ -778,22 +579,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
-/**
- * vidioc_try_fmt_vid_cap - set video capture format
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
- * @f: new format
- *
- * new video format is set which includes width and
- * field type. width is fixed to 720, no scaling.
- * Only UYVY is supported by this hardware.
- * the minimum height is 200, the maximum is 576 (PAL)
- *
- * return value: 0, no error
- *
- * -EINVAL, pixel or field format not supported
- *
- */
static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
@@ -840,42 +625,65 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
-/**
- * vidioc_s_fmt_vid_cap - set current video format parameters
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
- * @f: returned format information
- *
- * set new capture format
- * return value: 0, no error
- *
- * other, delivered by video DAC routine.
- */
static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct video_device *dev = priv;
struct sta2x11_vip *vip = video_get_drvdata(dev);
+ unsigned int t_stop, b_stop, pitch;
int ret;
ret = vidioc_try_fmt_vid_cap(file, priv, f);
if (ret)
return ret;
+ if (vb2_is_streaming(&vip->vb_vidq)) {
+ /* Can't change format during acquisition */
+ v4l2_err(&vip->v4l2_dev, "device busy\n");
+ return -EBUSY;
+ }
+
memcpy(&vip->format, &f->fmt.pix, sizeof(struct v4l2_pix_format));
+ switch (vip->format.field) {
+ case V4L2_FIELD_INTERLACED:
+ t_stop = ((vip->format.height / 2 - 1) << 16) |
+ (2 * vip->format.width - 1);
+ b_stop = t_stop;
+ pitch = 4 * vip->format.width;
+ break;
+ case V4L2_FIELD_TOP:
+ t_stop = ((vip->format.height - 1) << 16) |
+ (2 * vip->format.width - 1);
+ b_stop = (0 << 16) | (2 * vip->format.width - 1);
+ pitch = 2 * vip->format.width;
+ break;
+ case V4L2_FIELD_BOTTOM:
+ t_stop = (0 << 16) | (2 * vip->format.width - 1);
+ b_stop = (vip->format.height << 16) |
+ (2 * vip->format.width - 1);
+ pitch = 2 * vip->format.width;
+ break;
+ default:
+ v4l2_err(&vip->v4l2_dev, "unknown field format\n");
+ return -EINVAL;
+ }
+
+ spin_lock_irq(&vip->slock);
+ /* Y-X Top Field Offset */
+ reg_write(vip, DVP_TFO, 0);
+ /* Y-X Bottom Field Offset */
+ reg_write(vip, DVP_BFO, 0);
+ /* Y-X Top Field Stop*/
+ reg_write(vip, DVP_TFS, t_stop);
+ /* Y-X Bottom Field Stop */
+ reg_write(vip, DVP_BFS, b_stop);
+ /* Video Memory Pitch */
+ reg_write(vip, DVP_VMP, pitch);
+ spin_unlock_irq(&vip->slock);
+
return 0;
}
-/**
- * vidioc_g_fmt_vid_cap - get current video format parameters
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
- * @f: contains format information
- *
- * returns current video format parameters
- *
- * return value: 0, always successful
- */
static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
@@ -886,258 +694,175 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
-/**
- * vidioc_reqfs - request buffer
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
- * @p: video buffer
- *
- * Handling is done in generic videobuf layer.
- */
static int vidioc_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *p)
{
struct video_device *dev = priv;
struct sta2x11_vip *vip = video_get_drvdata(dev);
- return videobuf_reqbufs(&vip->vb_vidq, p);
+ return vb2_reqbufs(&vip->vb_vidq, p);
}
-/**
- * vidioc_querybuf - query buffer
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
- * @p: video buffer
- *
- * query buffer state.
- * Handling is done in generic videobuf layer.
- */
static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
{
struct video_device *dev = priv;
struct sta2x11_vip *vip = video_get_drvdata(dev);
- return videobuf_querybuf(&vip->vb_vidq, p);
+ return vb2_querybuf(&vip->vb_vidq, p);
}
-/**
- * vidioc_qbuf - queue a buffer
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
- * @p: video buffer
- *
- * Handling is done in generic videobuf layer.
- */
static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
{
struct video_device *dev = priv;
struct sta2x11_vip *vip = video_get_drvdata(dev);
- return videobuf_qbuf(&vip->vb_vidq, p);
+ return vb2_qbuf(&vip->vb_vidq, p);
}
-/**
- * vidioc_dqbuf - dequeue a buffer
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
- * @p: video buffer
- *
- * Handling is done in generic videobuf layer.
- */
static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
{
struct video_device *dev = priv;
struct sta2x11_vip *vip = video_get_drvdata(dev);
- return videobuf_dqbuf(&vip->vb_vidq, p, file->f_flags & O_NONBLOCK);
+ return vb2_dqbuf(&vip->vb_vidq, p, file->f_flags & O_NONBLOCK);
+}
+static int vidioc_create_bufs(struct file *file, void *fh,
+ struct v4l2_create_buffers *b)
+{
+ struct video_device *dev = video_devdata(file);
+ struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+ return vb2_create_bufs(&vip->vb_vidq, b);
}
-/**
- * vidioc_streamon - turn on streaming
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
- * @type: type of capture
- *
- * turn on streaming.
- * Handling is done in generic videobuf layer.
- */
static int vidioc_streamon(struct file *file, void *priv,
enum v4l2_buf_type type)
{
struct video_device *dev = priv;
struct sta2x11_vip *vip = video_get_drvdata(dev);
- return videobuf_streamon(&vip->vb_vidq);
+ return vb2_streamon(&vip->vb_vidq, type);
}
-/**
- * vidioc_streamoff - turn off streaming
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
- * @type: type of capture
- *
- * turn off streaming.
- * Handling is done in generic videobuf layer.
- */
static int vidioc_streamoff(struct file *file, void *priv,
enum v4l2_buf_type type)
{
struct video_device *dev = priv;
struct sta2x11_vip *vip = video_get_drvdata(dev);
- return videobuf_streamoff(&vip->vb_vidq);
+ return vb2_streamoff(&vip->vb_vidq, type);
}
-static const struct v4l2_file_operations vip_fops = {
- .owner = THIS_MODULE,
- .open = vip_open,
- .release = vip_close,
- .ioctl = video_ioctl2,
- .read = vip_read,
- .mmap = vip_mmap,
- .poll = vip_poll
-};
-
static const struct v4l2_ioctl_ops vip_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
- .vidioc_s_std = vidioc_s_std,
- .vidioc_g_std = vidioc_g_std,
- .vidioc_querystd = vidioc_querystd,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_enum_input = vidioc_enum_input,
- .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
- .vidioc_s_input = vidioc_s_input,
- .vidioc_g_input = vidioc_g_input,
+ /* FMT handling */
.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+ /* Buffer handlers */
.vidioc_reqbufs = vidioc_reqbufs,
.vidioc_querybuf = vidioc_querybuf,
.vidioc_qbuf = vidioc_qbuf,
.vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_create_bufs = vidioc_create_bufs,
+ /* Stream on/off */
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
+ /* Standard handling */
+ .vidioc_g_std = vidioc_g_std,
+ .vidioc_s_std = vidioc_s_std,
+ .vidioc_querystd = vidioc_querystd,
+ /* Input handling */
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
};
static struct video_device video_dev_template = {
- .name = DRV_NAME,
+ .name = KBUILD_MODNAME,
.release = video_device_release,
.fops = &vip_fops,
.ioctl_ops = &vip_ioctl_ops,
.tvnorms = V4L2_STD_ALL,
};
-/**
- * vip_irq - interrupt routine
- * @irq: Number of interrupt ( not used, correct number is assumed )
- * @vip: local data structure containing all information
- *
- * check for both frame interrupts set ( top and bottom ).
- * check FIFO overflow, but limit number of log messages after open.
- * signal a complete buffer if done.
- * dequeue a new buffer if available.
- * disable VIP if no buffer available.
- *
- * return value: IRQ_NONE, interrupt was not generated by VIP
- *
- * IRQ_HANDLED, interrupt done.
- */
+
static irqreturn_t vip_irq(int irq, struct sta2x11_vip *vip)
{
- u32 status, dma;
- unsigned long flags;
- struct videobuf_buffer *vb;
+ unsigned int status;
- status = REG_READ(vip, DVP_ITS);
+ status = reg_read(vip, DVP_ITS);
- if (!status) {
- pr_debug("VIP: irq ignored\n");
+ if (!status) /* No interrupt to handle */
return IRQ_NONE;
- }
- if (!vip->started)
- return IRQ_HANDLED;
-
- if (status & DVP_IT_VSB)
- vip->bcount++;
+ if (vip->closing) /* We are closing VIP */
+ return IRQ_NONE;
- if (status & DVP_IT_VST)
- vip->tcount++;
+ if (status & DVP_IT_FIFO)
+ if (vip->overflow++ > 5)
+ pr_info("VIP: fifo overflow\n");
- if ((DVP_IT_VSB | DVP_IT_VST) == (status & (DVP_IT_VST | DVP_IT_VSB))) {
+ if ((status & DVP_IT_VST) && (status & DVP_IT_VSB)) {
/* this is bad, we are too slow, hope the condition is gone
* on the next frame */
- pr_info("VIP: both irqs\n");
return IRQ_HANDLED;
}
- if (status & DVP_IT_FIFO) {
- if (5 > vip->overflow++)
- pr_info("VIP: fifo overflow\n");
+ if (status & DVP_IT_VST)
+ if ((++vip->tcount) < 2)
+ return IRQ_HANDLED;
+ if (status & DVP_IT_VSB) {
+ vip->bcount++;
+ return IRQ_HANDLED;
}
- if (2 > vip->tcount)
- return IRQ_HANDLED;
+ if (vip->active) { /* Acquisition is over on this buffer */
+ /* Disable acquisition */
+ reg_write(vip, DVP_CTL, reg_read(vip, DVP_CTL) & ~DVP_CTL_ENA);
+ /* Remove the active buffer from the list */
+ do_gettimeofday(&vip->active->vb.v4l2_buf.timestamp);
+ vip->active->vb.v4l2_buf.sequence = vip->sequence++;
+ vb2_buffer_done(&vip->active->vb, VB2_BUF_STATE_DONE);
+ }
- if (status & DVP_IT_VSB)
- return IRQ_HANDLED;
+ return IRQ_HANDLED;
+}
- spin_lock_irqsave(&vip->slock, flags);
+static void sta2x11_vip_init_buffer(struct sta2x11_vip *vip)
+{
+ memset(&vip->vb_vidq, 0, sizeof(struct vb2_queue));
+ vip->vb_vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ vip->vb_vidq.io_modes = VB2_MMAP | VB2_READ;
+ vip->vb_vidq.drv_priv = vip;
+ vip->vb_vidq.buf_struct_size = sizeof(struct vip_buffer);
+ vip->vb_vidq.ops = &vip_video_qops;
+ vip->vb_vidq.mem_ops = &vb2_dma_streaming_memops;
+ vb2_queue_init(&vip->vb_vidq);
+ INIT_LIST_HEAD(&vip->buffer_list);
+ spin_lock_init(&vip->lock);
+}
- REG_WRITE(vip, DVP_CTL, REG_READ(vip, DVP_CTL) & ~DVP_CTL_ENA);
- if (vip->active) {
- do_gettimeofday(&vip->active->ts);
- vip->active->field_count++;
- vip->active->state = VIDEOBUF_DONE;
- wake_up(&vip->active->done);
- vip->active = NULL;
- }
- if (!vip->closing) {
- if (list_empty(&vip->capture))
- goto done;
-
- vb = list_first_entry(&vip->capture, struct videobuf_buffer,
- queue);
- if (NULL == vb) {
- pr_info("VIP: no buffer\n");
- goto done;
- }
- vb->state = VIDEOBUF_ACTIVE;
- list_del(&vb->queue);
- vip->active = vb;
- dma = videobuf_to_dma_contig(vb);
- switch (vip->format.field) {
- case V4L2_FIELD_INTERLACED:
- REG_WRITE(vip, DVP_VTP, dma);
- REG_WRITE(vip, DVP_VBP, dma + vip->format.width * 2);
- break;
- case V4L2_FIELD_TOP:
- case V4L2_FIELD_BOTTOM:
- REG_WRITE(vip, DVP_VTP, dma);
- REG_WRITE(vip, DVP_VBP, dma);
- break;
- default:
- pr_warning("VIP: unknown field format\n");
- goto done;
- break;
- }
- REG_WRITE(vip, DVP_CTL, REG_READ(vip, DVP_CTL) | DVP_CTL_ENA);
+static int sta2x11_vip_init_controls(struct sta2x11_vip *vip)
+{
+ /*
+ * Inititialize an empty control so VIP can inerithing controls
+ * from ADV7180
+ */
+ v4l2_ctrl_handler_init(&vip->ctrl_hdl, 0);
+
+ vip->v4l2_dev.ctrl_handler = &vip->ctrl_hdl;
+ if (vip->ctrl_hdl.error) {
+ int err = vip->ctrl_hdl.error;
+
+ v4l2_ctrl_handler_free(&vip->ctrl_hdl);
+ return err;
}
-done:
- spin_unlock_irqrestore(&vip->slock, flags);
- return IRQ_HANDLED;
+
+ return 0;
}
-/**
- * vip_gpio_reserve - reserve gpio pin
- * @dev: device
- * @pin: GPIO pin number
- * @dir: direction, input or output
- * @name: GPIO pin name
- *
- */
static int vip_gpio_reserve(struct device *dev, int pin, int dir,
const char *name)
{
@@ -1170,13 +895,6 @@ static int vip_gpio_reserve(struct device *dev, int pin, int dir,
return 0;
}
-/**
- * vip_gpio_release - release gpio pin
- * @dev: device
- * @pin: GPIO pin number
- * @name: GPIO pin name
- *
- */
static void vip_gpio_release(struct device *dev, int pin, const char *name)
{
if (pin != -1) {
@@ -1186,25 +904,6 @@ static void vip_gpio_release(struct device *dev, int pin, const char *name)
}
}
-/**
- * sta2x11_vip_init_one - init one instance of video device
- * @pdev: PCI device
- * @ent: (not used)
- *
- * allocate reset pins for DAC.
- * Reset video DAC, this is done via reset line.
- * allocate memory for managing device
- * request interrupt
- * map IO region
- * register device
- * find and initialize video DAC
- *
- * return value: 0, no error
- *
- * -ENOMEM, no memory
- *
- * -ENODEV, device could not be detected or registered
- */
static int __devinit sta2x11_vip_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -1212,10 +911,17 @@ static int __devinit sta2x11_vip_init_one(struct pci_dev *pdev,
struct sta2x11_vip *vip;
struct vip_config *config;
+ /* Check if hardware support 26-bit DMA */
+ if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(26))) {
+ dev_err(&pdev->dev, "26-bit DMA addressing not available\n");
+ return -EINVAL;
+ }
+ /* Enable PCI */
ret = pci_enable_device(pdev);
if (ret)
return ret;
+ /* Get VIP platform data */
config = dev_get_platdata(&pdev->dev);
if (!config) {
dev_info(&pdev->dev, "VIP slot disabled\n");
@@ -1223,6 +929,7 @@ static int __devinit sta2x11_vip_init_one(struct pci_dev *pdev,
goto disable;
}
+ /* Power configuration */
ret = vip_gpio_reserve(&pdev->dev, config->pwr_pin, 0,
config->pwr_name);
if (ret)
@@ -1237,7 +944,6 @@ static int __devinit sta2x11_vip_init_one(struct pci_dev *pdev,
goto disable;
}
}
-
if (config->pwr_pin != -1) {
/* Datasheet says 5ms between PWR and RST */
usleep_range(5000, 25000);
@@ -1251,17 +957,20 @@ static int __devinit sta2x11_vip_init_one(struct pci_dev *pdev,
}
usleep_range(5000, 25000);
+ /* Allocate a new VIP instance */
vip = kzalloc(sizeof(struct sta2x11_vip), GFP_KERNEL);
if (!vip) {
ret = -ENOMEM;
goto release_gpios;
}
-
vip->pdev = pdev;
vip->std = V4L2_STD_PAL;
vip->format = formats_50[0];
vip->config = config;
+ ret = sta2x11_vip_init_controls(vip);
+ if (ret)
+ goto free_mem;
if (v4l2_device_register(&pdev->dev, &vip->v4l2_dev))
goto free_mem;
@@ -1271,46 +980,49 @@ static int __devinit sta2x11_vip_init_one(struct pci_dev *pdev,
pci_set_master(pdev);
- ret = pci_request_regions(pdev, DRV_NAME);
+ ret = pci_request_regions(pdev, KBUILD_MODNAME);
if (ret)
goto unreg;
vip->iomem = pci_iomap(pdev, 0, 0x100);
if (!vip->iomem) {
- ret = -ENOMEM; /* FIXME */
+ ret = -ENOMEM;
goto release;
}
pci_enable_msi(pdev);
- INIT_LIST_HEAD(&vip->capture);
+ /* Initialize buffer */
+ sta2x11_vip_init_buffer(vip);
+
spin_lock_init(&vip->slock);
- mutex_init(&vip->mutex);
- vip->started = 0;
vip->disabled = 0;
ret = request_irq(pdev->irq,
(irq_handler_t) vip_irq,
- IRQF_SHARED, DRV_NAME, vip);
+ IRQF_SHARED, KBUILD_MODNAME, vip);
if (ret) {
dev_err(&pdev->dev, "request_irq failed\n");
ret = -ENODEV;
goto unmap;
}
+ /* Alloc, initialize and register video device */
vip->video_dev = video_device_alloc();
if (!vip->video_dev) {
ret = -ENOMEM;
goto release_irq;
}
- *(vip->video_dev) = video_dev_template;
+ vip->video_dev = &video_dev_template;
+ vip->video_dev->v4l2_dev = &vip->v4l2_dev;
video_set_drvdata(vip->video_dev, vip);
ret = video_register_device(vip->video_dev, VFL_TYPE_GRABBER, -1);
if (ret)
goto vrelease;
+ /* Get ADV7180 subdevice */
vip->adapter = i2c_get_adapter(vip->config->i2c_id);
if (!vip->adapter) {
ret = -ENODEV;
@@ -1328,10 +1040,9 @@ static int __devinit sta2x11_vip_init_one(struct pci_dev *pdev,
}
i2c_put_adapter(vip->adapter);
-
v4l2_subdev_call(vip->decoder, core, init, 0);
- pr_info("STA2X11 Video Input Port (VIP) loaded\n");
+ dev_info(&pdev->dev, "STA2X11 Video Input Port (VIP) loaded\n");
return 0;
vunreg:
@@ -1345,8 +1056,8 @@ release_irq:
free_irq(pdev->irq, vip);
pci_disable_msi(pdev);
unmap:
+ vb2_queue_release(&vip->vb_vidq);
pci_iounmap(pdev, vip->iomem);
- mutex_destroy(&vip->mutex);
release:
pci_release_regions(pdev);
unreg:
@@ -1364,18 +1075,6 @@ disable:
return ret;
}
-/**
- * sta2x11_vip_remove_one - release device
- * @pdev: PCI device
- *
- * Undo everything done in .._init_one
- *
- * unregister video device
- * free interrupt
- * unmap ioadresses
- * free memory
- * free GPIO pins
- */
static void __devexit sta2x11_vip_remove_one(struct pci_dev *pdev)
{
struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
@@ -1387,11 +1086,11 @@ static void __devexit sta2x11_vip_remove_one(struct pci_dev *pdev)
/*do not call video_device_release() here, is already done */
free_irq(pdev->irq, vip);
pci_disable_msi(pdev);
+ vb2_queue_release(&vip->vb_vidq);
pci_iounmap(pdev, vip->iomem);
pci_release_regions(pdev);
v4l2_device_unregister(&vip->v4l2_dev);
- mutex_destroy(&vip->mutex);
vip_gpio_release(&pdev->dev, vip->config->pwr_pin,
vip->config->pwr_name);
@@ -1407,18 +1106,12 @@ static void __devexit sta2x11_vip_remove_one(struct pci_dev *pdev)
#ifdef CONFIG_PM
-/**
- * sta2x11_vip_suspend - set device into power save mode
- * @pdev: PCI device
- * @state: new state of device
+/*
*
* all relevant registers are saved and an attempt to set a new state is made.
*
* return value: 0 always indicate success,
* even if device could not be disabled. (workaround for hardware problem)
- *
- * reurn value : 0, always succesful, even if hardware does not not support
- * power down mode.
*/
static int sta2x11_vip_suspend(struct pci_dev *pdev, pm_message_t state)
{
@@ -1429,15 +1122,15 @@ static int sta2x11_vip_suspend(struct pci_dev *pdev, pm_message_t state)
int i;
spin_lock_irqsave(&vip->slock, flags);
- vip->register_save_area[0] = REG_READ(vip, DVP_CTL);
- REG_WRITE(vip, DVP_CTL, vip->register_save_area[0] & DVP_CTL_DIS);
- vip->register_save_area[SAVE_COUNT] = REG_READ(vip, DVP_ITM);
- REG_WRITE(vip, DVP_ITM, 0);
+ vip->register_save_area[0] = reg_read(vip, DVP_CTL);
+ reg_write(vip, DVP_CTL, vip->register_save_area[0] & DVP_CTL_DIS);
+ vip->register_save_area[SAVE_COUNT] = reg_read(vip, DVP_ITM);
+ reg_write(vip, DVP_ITM, 0);
for (i = 1; i < SAVE_COUNT; i++)
- vip->register_save_area[i] = REG_READ(vip, 4 * i);
+ vip->register_save_area[i] = reg_read(vip, 4 * i);
for (i = 0; i < AUX_COUNT; i++)
vip->register_save_area[SAVE_COUNT + IRQ_COUNT + i] =
- REG_READ(vip, registers_to_save[i]);
+ reg_read(vip, registers_to_save[i]);
spin_unlock_irqrestore(&vip->slock, flags);
/* save pci state */
pci_save_state(pdev);
@@ -1453,16 +1146,9 @@ static int sta2x11_vip_suspend(struct pci_dev *pdev, pm_message_t state)
return 0;
}
-/**
- * sta2x11_vip_resume - resume device operation
- * @pdev : PCI device
- *
+/*
* re-enable device, set PCI state to powered and restore registers.
* resume normal device operation afterwards.
- *
- * return value: 0, no error.
- *
- * other, could not set device to power on state.
*/
static int sta2x11_vip_resume(struct pci_dev *pdev)
{
@@ -1497,12 +1183,12 @@ static int sta2x11_vip_resume(struct pci_dev *pdev)
spin_lock_irqsave(&vip->slock, flags);
for (i = 1; i < SAVE_COUNT; i++)
- REG_WRITE(vip, 4 * i, vip->register_save_area[i]);
+ reg_write(vip, 4 * i, vip->register_save_area[i]);
for (i = 0; i < AUX_COUNT; i++)
- REG_WRITE(vip, registers_to_save[i],
+ reg_write(vip, registers_to_save[i],
vip->register_save_area[SAVE_COUNT + IRQ_COUNT + i]);
- REG_WRITE(vip, DVP_CTL, vip->register_save_area[0]);
- REG_WRITE(vip, DVP_ITM, vip->register_save_area[SAVE_COUNT]);
+ reg_write(vip, DVP_CTL, vip->register_save_area[0]);
+ reg_write(vip, DVP_ITM, vip->register_save_area[SAVE_COUNT]);
spin_unlock_irqrestore(&vip->slock, flags);
return 0;
}
@@ -1515,7 +1201,7 @@ static DEFINE_PCI_DEVICE_TABLE(sta2x11_vip_pci_tbl) = {
};
static struct pci_driver sta2x11_vip_driver = {
- .name = DRV_NAME,
+ .name = KBUILD_MODNAME,
.probe = sta2x11_vip_init_one,
.remove = __devexit_p(sta2x11_vip_remove_one),
.id_table = sta2x11_vip_pci_tbl,
@@ -1543,7 +1229,7 @@ late_initcall_sync(sta2x11_vip_init_module);
#endif
MODULE_DESCRIPTION("STA2X11 Video Input Port driver");
-MODULE_AUTHOR("Wind River");
+MODULE_AUTHOR("Federico Vaga <federico.vaga@gmail.com>");
MODULE_LICENSE("GPL v2");
MODULE_SUPPORTED_DEVICE("sta2x11 video input");
MODULE_VERSION(DRV_VERSION);
--
1.7.11.2
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH 1/3] [media] adv7180: remove {query/g_/s_}ctrl
2012-07-31 20:17 ` [PATCH 1/3] [media] adv7180: remove {query/g_/s_}ctrl Federico Vaga
@ 2012-07-31 20:20 ` Federico Vaga
2012-08-12 1:46 ` Mauro Carvalho Chehab
0 siblings, 1 reply; 22+ messages in thread
From: Federico Vaga @ 2012-07-31 20:20 UTC (permalink / raw)
To: Mauro Carvalho Chehab, Pawel Osciak, Marek Szyprowski,
Hans Verkuil
Cc: Giancarlo Asnaghi, linux-media, linux-kernel, Jonathan Corbet,
Federico Vaga
I'm sorry for the email duplication, I press the wrong key on git-send email.
Ignore these emails. Sorry
--
Federico Vaga
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: Update VIP to videobuf2 and control framework
2012-07-31 20:17 Update VIP to videobuf2 and control framework Federico Vaga
` (2 preceding siblings ...)
2012-07-31 20:17 ` [PATCH 3/3] [media] sta2x11_vip: convert to videobuf2 and control framework Federico Vaga
@ 2012-07-31 20:27 ` Federico Vaga
2012-08-01 6:41 ` Hans Verkuil
4 siblings, 0 replies; 22+ messages in thread
From: Federico Vaga @ 2012-07-31 20:27 UTC (permalink / raw)
To: Mauro Carvalho Chehab, Pawel Osciak, Marek Szyprowski,
Hans Verkuil
Cc: Giancarlo Asnaghi, linux-media, linux-kernel, Jonathan Corbet
I use git send-email command to send patches but I think I made a
mistake. If something
is wrong or confused please tell me and I try to resend all the
patches hopefully without mistake. Sorry again.
2012/7/31 Federico Vaga <federico.vaga@gmail.com>:
> As suggested I moved the Video Buffer Input (VIP) of the STA2X11 board to the
> videobuf2. This patch series is an RFC.
>
> The first patch is just an update to the adv7180 because the VIP (the only
> user) now use the control framework so query{g_|s_|ctrl} are not necessery.
>
> The second patch adds a new memory allocator for the videobuf2. I name it
> videobuf2-dma-streaming but I think "streaming" is not the best choice, so
> suggestions are welcome. My inspiration for this buffer come from
> videobuf-dma-contig (cached) version. After I made this buffer I found the
> videobuf2-dma-nc made by Jonathan Corbet and I improve the allocator with
> some suggestions (http://patchwork.linuxtv.org/patch/7441/). The VIP doesn't
> work with videobu2-dma-contig and I think this solution is easier the sg.
>
> The third patch updates the VIP to videobuf2 and control framework. I made also
> some restyling to the driver and change some mechanism so I take the ownership
> of the driver and I add the copyright of ST Microelectronics. Some trivial
> code is unchanged. The patch probably needs some extra update.
> I add the control framework to the VIP but without any control. I add it to
> inherit controls from adv7180.
>
--
Federico Vaga
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: Update VIP to videobuf2 and control framework
2012-07-31 20:17 Update VIP to videobuf2 and control framework Federico Vaga
` (3 preceding siblings ...)
2012-07-31 20:27 ` Update VIP " Federico Vaga
@ 2012-08-01 6:41 ` Hans Verkuil
2012-08-01 13:04 ` Jonathan Corbet
2012-08-05 17:11 ` Federico Vaga
4 siblings, 2 replies; 22+ messages in thread
From: Hans Verkuil @ 2012-08-01 6:41 UTC (permalink / raw)
To: Federico Vaga
Cc: Mauro Carvalho Chehab, Pawel Osciak, Marek Szyprowski,
Hans Verkuil, Giancarlo Asnaghi, linux-media, linux-kernel,
Jonathan Corbet
On Tue July 31 2012 22:17:06 Federico Vaga wrote:
> As suggested I moved the Video Buffer Input (VIP) of the STA2X11 board to the
> videobuf2. This patch series is an RFC.
Thank you very much for working on this! Much appreciated!
> The first patch is just an update to the adv7180 because the VIP (the only
> user) now use the control framework so query{g_|s_|ctrl} are not necessery.
For this patch:
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> The second patch adds a new memory allocator for the videobuf2. I name it
> videobuf2-dma-streaming but I think "streaming" is not the best choice, so
> suggestions are welcome. My inspiration for this buffer come from
> videobuf-dma-contig (cached) version. After I made this buffer I found the
> videobuf2-dma-nc made by Jonathan Corbet and I improve the allocator with
> some suggestions (http://patchwork.linuxtv.org/patch/7441/). The VIP doesn't
> work with videobu2-dma-contig and I think this solution is easier the sg.
I leave this to the vb2 experts. It's not obvious to me why we would need
a fourth memory allocator.
> The third patch updates the VIP to videobuf2 and control framework. I made also
> some restyling to the driver and change some mechanism so I take the ownership
> of the driver and I add the copyright of ST Microelectronics. Some trivial
> code is unchanged. The patch probably needs some extra update.
> I add the control framework to the VIP but without any control. I add it to
> inherit controls from adv7180.
Did you run the latest v4l2-compliance tool from the v4l-utils.git repository
over your driver? I'm sure you didn't since VIP is missing support for control
events and v4l2-compliance would certainly complain about that.
Always check with v4l2-compliance whenever you make changes! It's continuously
improved as well, so a periodic check wouldn't hurt.
Also take a look at the new vb2 helper functions in media/videobuf2-core.h:
it is likely that you can use those to simplify your driver. They are used in
e.g. vivi, so take a look there.
Regards,
Hans
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: Update VIP to videobuf2 and control framework
2012-08-01 6:41 ` Hans Verkuil
@ 2012-08-01 13:04 ` Jonathan Corbet
2012-08-16 11:29 ` Federico Vaga
2012-08-05 17:11 ` Federico Vaga
1 sibling, 1 reply; 22+ messages in thread
From: Jonathan Corbet @ 2012-08-01 13:04 UTC (permalink / raw)
To: Hans Verkuil
Cc: Federico Vaga, Mauro Carvalho Chehab, Pawel Osciak,
Marek Szyprowski, Hans Verkuil, Giancarlo Asnaghi, linux-media,
linux-kernel
On Wed, 1 Aug 2012 08:41:56 +0200
Hans Verkuil <hverkuil@xs4all.nl> wrote:
> > The second patch adds a new memory allocator for the videobuf2. I name it
> > videobuf2-dma-streaming but I think "streaming" is not the best choice, so
> > suggestions are welcome. My inspiration for this buffer come from
> > videobuf-dma-contig (cached) version. After I made this buffer I found the
> > videobuf2-dma-nc made by Jonathan Corbet and I improve the allocator with
> > some suggestions (http://patchwork.linuxtv.org/patch/7441/). The VIP doesn't
> > work with videobu2-dma-contig and I think this solution is easier the sg.
>
> I leave this to the vb2 experts. It's not obvious to me why we would need
> a fourth memory allocator.
I first wrote my version after observing that performance dropped by a
factor of three on the OLPC XO 1.75 when using contiguous, coherent
memory. If the architecture needs to turn off caching, things really slow
down, to the point that it's unusable. There's no real reason why a V4L2
device shouldn't be able to use streaming mappings in this situation; it
performs better and doesn't eat into the limited amounts of coherent DMA
space available on some systems.
I never got my version into a mergeable state only because I finally
figured out how to bludgeon the hardware into doing s/g DMA and didn't
need it anymore. But I think it's a worthwhile functionality to have,
and, with CMA, it could be the preferred mode for a number of devices.
jon
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: Update VIP to videobuf2 and control framework
2012-08-01 6:41 ` Hans Verkuil
2012-08-01 13:04 ` Jonathan Corbet
@ 2012-08-05 17:11 ` Federico Vaga
2012-08-06 7:26 ` Hans Verkuil
1 sibling, 1 reply; 22+ messages in thread
From: Federico Vaga @ 2012-08-05 17:11 UTC (permalink / raw)
To: Hans Verkuil
Cc: Mauro Carvalho Chehab, Pawel Osciak, Marek Szyprowski,
Hans Verkuil, Giancarlo Asnaghi, linux-media, linux-kernel,
Jonathan Corbet
Hi Hans,
> Did you run the latest v4l2-compliance tool from the v4l-utils.git
> repository over your driver? I'm sure you didn't since VIP is missing
> support for control events and v4l2-compliance would certainly
> complain about that.
>
> Always check with v4l2-compliance whenever you make changes! It's
> continuously improved as well, so a periodic check wouldn't hurt.
I applied all your suggestions, and some extra simplification; now I'm
running v4l2-compliance but I have this error:
Allow for multiple opens:
test second video open: OK
test VIDIOC_QUERYCAP: OK
fail: v4l2-compliance.cpp(322): doioctl(node,
VIDIOC_G_PRIORITY, &prio)
test VIDIOC_G/S_PRIORITY: FAIL
which I don't undestand. I don't have vidio_{g|s}_priority functions in
my implementation. And I'm using the V4L2_FL_USE_FH_PRIO flag as
suggested in the documentation:
---------------
- flags: optional. Set to V4L2_FL_USE_FH_PRIO if you want to let the
framework handle the VIDIOC_G/S_PRIORITY ioctls. This requires that you
use struct v4l2_fh. Eventually this flag will disappear once all drivers
use the core priority handling. But for now it has to be set explicitly.
--------------
--
Federico Vaga
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: Update VIP to videobuf2 and control framework
2012-08-05 17:11 ` Federico Vaga
@ 2012-08-06 7:26 ` Hans Verkuil
2012-08-06 7:38 ` Federico Vaga
0 siblings, 1 reply; 22+ messages in thread
From: Hans Verkuil @ 2012-08-06 7:26 UTC (permalink / raw)
To: Federico Vaga
Cc: Mauro Carvalho Chehab, Pawel Osciak, Marek Szyprowski,
Hans Verkuil, Giancarlo Asnaghi, linux-media, linux-kernel,
Jonathan Corbet
On Sun August 5 2012 19:11:19 Federico Vaga wrote:
> Hi Hans,
>
> > Did you run the latest v4l2-compliance tool from the v4l-utils.git
> > repository over your driver? I'm sure you didn't since VIP is missing
> > support for control events and v4l2-compliance would certainly
> > complain about that.
> >
> > Always check with v4l2-compliance whenever you make changes! It's
> > continuously improved as well, so a periodic check wouldn't hurt.
>
> I applied all your suggestions, and some extra simplification; now I'm
> running v4l2-compliance but I have this error:
>
>
> Allow for multiple opens:
> test second video open: OK
> test VIDIOC_QUERYCAP: OK
> fail: v4l2-compliance.cpp(322): doioctl(node,
> VIDIOC_G_PRIORITY, &prio)
> test VIDIOC_G/S_PRIORITY: FAIL
>
>
> which I don't undestand. I don't have vidio_{g|s}_priority functions in
> my implementation. And I'm using the V4L2_FL_USE_FH_PRIO flag as
> suggested in the documentation:
>
> ---------------
> - flags: optional. Set to V4L2_FL_USE_FH_PRIO if you want to let the
> framework handle the VIDIOC_G/S_PRIORITY ioctls. This requires that you
> use struct v4l2_fh.
^^^^^^^^^^^^^^^^^^
Are you using struct v4l2_fh? The version you posted didn't. You need this
anyway to implement control events.
Regards,
Hans
> Eventually this flag will disappear once all drivers
> use the core priority handling. But for now it has to be set explicitly.
> --------------
>
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: Update VIP to videobuf2 and control framework
2012-08-06 7:38 ` Federico Vaga
@ 2012-08-06 7:36 ` Hans Verkuil
2012-08-06 8:20 ` Federico Vaga
0 siblings, 1 reply; 22+ messages in thread
From: Hans Verkuil @ 2012-08-06 7:36 UTC (permalink / raw)
To: Federico Vaga
Cc: Mauro Carvalho Chehab, Pawel Osciak, Marek Szyprowski,
Hans Verkuil, Giancarlo Asnaghi, linux-media, linux-kernel,
Jonathan Corbet
On Mon August 6 2012 09:38:10 Federico Vaga wrote:
>
> > > I applied all your suggestions, and some extra simplification;
> > > [...]
>
> > > ---------------
> > > - flags: optional. Set to V4L2_FL_USE_FH_PRIO if you want to let the
> > > framework handle the VIDIOC_G/S_PRIORITY ioctls. This requires that
> > > you use struct v4l2_fh.
> >
> > ^^^^^^^^^^^^^^^^^^
> >
> > Are you using struct v4l2_fh? The version you posted didn't. You need
> > this anyway to implement control events.
>
> Yes I'm using it now, it is part of the extra simplification that I did.
In that case I need to see your latest version of the source code to see
why it doesn't work.
Regards,
Hans
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: Update VIP to videobuf2 and control framework
2012-08-06 7:26 ` Hans Verkuil
@ 2012-08-06 7:38 ` Federico Vaga
2012-08-06 7:36 ` Hans Verkuil
0 siblings, 1 reply; 22+ messages in thread
From: Federico Vaga @ 2012-08-06 7:38 UTC (permalink / raw)
To: Hans Verkuil
Cc: Mauro Carvalho Chehab, Pawel Osciak, Marek Szyprowski,
Hans Verkuil, Giancarlo Asnaghi, linux-media, linux-kernel,
Jonathan Corbet
> > I applied all your suggestions, and some extra simplification;
> > [...]
> > ---------------
> > - flags: optional. Set to V4L2_FL_USE_FH_PRIO if you want to let the
> > framework handle the VIDIOC_G/S_PRIORITY ioctls. This requires that
> > you use struct v4l2_fh.
>
> ^^^^^^^^^^^^^^^^^^
>
> Are you using struct v4l2_fh? The version you posted didn't. You need
> this anyway to implement control events.
Yes I'm using it now, it is part of the extra simplification that I did.
--
Federico Vaga
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 3/3 v2] [media] sta2x11_vip: convert to videobuf2 and control framework
2012-07-31 20:17 ` [PATCH 3/3] [media] sta2x11_vip: convert to videobuf2 and control framework Federico Vaga
@ 2012-08-06 8:17 ` Federico Vaga
2012-08-06 8:42 ` Hans Verkuil
0 siblings, 1 reply; 22+ messages in thread
From: Federico Vaga @ 2012-08-06 8:17 UTC (permalink / raw)
To: Mauro Carvalho Chehab, Pawel Osciak, Marek Szyprowski,
Hans Verkuil
Cc: Giancarlo Asnaghi, linux-media, linux-kernel, Jonathan Corbet,
Federico Vaga
Signed-off-by: Federico Vaga <federico.vaga@gmail.com>
Acked-by: Giancarlo Asnaghi <giancarlo.asnaghi@st.com>
---
drivers/media/video/sta2x11_vip.c | 1239 +++++++++++++------------------------
1 file modificato, 414 inserzioni(+), 825 rimozioni(-)
diff --git a/drivers/media/video/sta2x11_vip.c b/drivers/media/video/sta2x11_vip.c
index 4c10205..ffd9f0a 100644
--- a/drivers/media/video/sta2x11_vip.c
+++ b/drivers/media/video/sta2x11_vip.c
@@ -1,6 +1,7 @@
/*
* This is the driver for the STA2x11 Video Input Port.
*
+ * Copyright (C) 2012 ST Microelectronics
* Copyright (C) 2010 WindRiver Systems, Inc.
*
* This program is free software; you can redistribute it and/or modify it
@@ -19,36 +20,30 @@
* The full GNU General Public License is included in this distribution in
* the file called "COPYING".
*
- * Author: Andreas Kies <andreas.kies@windriver.com>
- * Vlad Lungu <vlad.lungu@windriver.com>
- *
*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/vmalloc.h>
-
#include <linux/videodev2.h>
-
#include <linux/kmod.h>
-
#include <linux/pci.h>
#include <linux/interrupt.h>
-#include <linux/mutex.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
#include <media/v4l2-ioctl.h>
-#include <media/videobuf-dma-contig.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+#include <media/videobuf2-dma-streaming.h>
#include "sta2x11_vip.h"
-#define DRV_NAME "sta2x11_vip"
#define DRV_VERSION "1.3"
#ifndef PCI_DEVICE_ID_STMICRO_VIP
@@ -63,8 +58,8 @@
#define DVP_TFS 0x08
#define DVP_BFO 0x0C
#define DVP_BFS 0x10
-#define DVP_VTP 0x14
-#define DVP_VBP 0x18
+#define DVP_VTP 0x14
+#define DVP_VBP 0x18
#define DVP_VMP 0x1C
#define DVP_ITM 0x98
#define DVP_ITS 0x9C
@@ -84,44 +79,24 @@
#define DVP_HLFLN_SD 0x00000001
-#define REG_WRITE(vip, reg, value) iowrite32((value), (vip->iomem)+(reg))
-#define REG_READ(vip, reg) ioread32((vip->iomem)+(reg))
-
#define SAVE_COUNT 8
#define AUX_COUNT 3
#define IRQ_COUNT 1
-/**
- * struct sta2x11_vip - All internal data for one instance of device
- * @v4l2_dev: device registered in v4l layer
- * @video_dev: properties of our device
- * @pdev: PCI device
- * @adapter: contains I2C adapter information
- * @register_save_area: All relevant register are saved here during suspend
- * @decoder: contains information about video DAC
- * @format: pixel format, fixed UYVY
- * @std: video standard (e.g. PAL/NTSC)
- * @input: input line for video signal ( 0 or 1 )
- * @users: Number of open of device ( max. 1 )
- * @disabled: Device is in power down state
- * @mutex: ensures exclusive opening of device
- * @slock: for excluse acces of registers
- * @vb_vidq: queue maintained by videobuf layer
- * @capture: linked list of capture buffer
- * @active: struct videobuf_buffer currently beingg filled
- * @started: device is ready to capture frame
- * @closing: device will be shut down
- * @tcount: Number of top frames
- * @bcount: Number of bottom frames
- * @overflow: Number of FIFO overflows
- * @mem_spare: small buffer of unused frame
- * @dma_spare: dma addres of mem_spare
- * @iomem: hardware base address
- * @config: I2C and gpio config from platform
- *
- * All non-local data is accessed via this structure.
- */
+struct vip_buffer {
+ struct vb2_buffer vb;
+ struct list_head list;
+ dma_addr_t dma;
+};
+static inline struct vip_buffer *to_vip_buffer(struct vb2_buffer *vb2)
+{
+ return container_of(vb2, struct vip_buffer, vb);
+}
+
+struct sta2x11_vip_fh {
+ struct v4l2_fh fh;
+};
struct sta2x11_vip {
struct v4l2_device v4l2_dev;
struct video_device *video_dev;
@@ -129,21 +104,27 @@ struct sta2x11_vip {
struct i2c_adapter *adapter;
unsigned int register_save_area[IRQ_COUNT + SAVE_COUNT + AUX_COUNT];
struct v4l2_subdev *decoder;
- struct v4l2_pix_format format;
- v4l2_std_id std;
- unsigned int input;
- int users;
- int disabled;
- struct mutex mutex; /* exclusive access during open */
- spinlock_t slock; /* spin lock for hardware and queue access */
- struct videobuf_queue vb_vidq;
- struct list_head capture;
- struct videobuf_buffer *active;
- int started, closing, tcount, bcount;
+ struct v4l2_ctrl_handler ctrl_hdl;
+
+
+ struct v4l2_pix_format format; /* pixel format, fixed UYVY */
+ v4l2_std_id std; /* Video standard (PAL/NTSC)*/
+ unsigned int input; /* Input line (0 or 1) */
+ int disabled; /* 1 disabled 0 enabled */
+ spinlock_t slock; /* spin lock for hardware */
+
+ struct vb2_alloc_ctx *alloc_ctx;
+ struct vb2_queue vb_vidq; /* queue maintaned by videobuf2 */
+ struct list_head buffer_list; /* list of buffers */
+ unsigned int sequence;
+ struct vip_buffer *active; /* current active buffer */
+ spinlock_t lock; /* Used in videobuf2 callback */
+
+ /* Interrupt counters */
+ int tcount, bcount;
int overflow;
- void *mem_spare;
- dma_addr_t dma_spare;
- void *iomem;
+
+ void *iomem; /* I/O Memory */
struct vip_config *config;
};
@@ -206,360 +187,221 @@ static struct v4l2_pix_format formats_60[] = {
.colorspace = V4L2_COLORSPACE_SMPTE170M},
};
-/**
- * buf_setup - Get size and number of video buffer
- * @vq: queue in videobuf
- * @count: Number of buffers (1..MAX_FRAMES).
- * 0 use default value.
- * @size: size of buffer in bytes
- *
- * returns size and number of buffers
- * a preset value of 0 returns the default number.
- * return value: 0, always succesfull.
- */
-static int buf_setup(struct videobuf_queue *vq, unsigned int *count,
- unsigned int *size)
+/* Write VIP register */
+static inline void reg_write(struct sta2x11_vip *vip, unsigned int reg, u32 val)
{
- struct sta2x11_vip *vip = vq->priv_data;
-
- *size = vip->format.width * vip->format.height * 2;
- if (0 == *count || MAX_FRAMES < *count)
- *count = MAX_FRAMES;
- return 0;
-};
-
-/**
- * buf_prepare - prepare buffer for usage
- * @vq: queue in videobuf layer
- * @vb: buffer to be prepared
- * @field: type of video data (interlaced/non-interlaced)
- *
- * Allocate or realloc buffer
- * return value: 0, successful.
- *
- * -EINVAL, supplied buffer is too small.
- *
- * other, buffer could not be locked.
- */
-static int buf_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
- enum v4l2_field field)
+ iowrite32((val), (vip->iomem)+(reg));
+}
+/* Read VIP register */
+static inline u32 reg_read(struct sta2x11_vip *vip, unsigned int reg)
{
- struct sta2x11_vip *vip = vq->priv_data;
- int ret;
-
- vb->size = vip->format.width * vip->format.height * 2;
- if ((0 != vb->baddr) && (vb->bsize < vb->size))
- return -EINVAL;
- vb->width = vip->format.width;
- vb->height = vip->format.height;
- vb->field = field;
-
- if (VIDEOBUF_NEEDS_INIT == vb->state) {
- ret = videobuf_iolock(vq, vb, NULL);
- if (ret)
- goto fail;
- }
- vb->state = VIDEOBUF_PREPARED;
- return 0;
-fail:
- videobuf_dma_contig_free(vq, vb);
- vb->state = VIDEOBUF_NEEDS_INIT;
- return ret;
+ return ioread32((vip->iomem)+(reg));
}
-
-/**
- * buf_queu - queue buffer for filling
- * @vq: queue in videobuf layer
- * @vb: buffer to be queued
- *
- * if capturing is already running, the buffer will be queued. Otherwise
- * capture is started and the buffer is used directly.
- */
-static void buf_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+/* Start DMA acquisition */
+static void start_dma(struct sta2x11_vip *vip, struct vip_buffer *vip_buf)
{
- struct sta2x11_vip *vip = vq->priv_data;
- u32 dma;
+ unsigned long offset = 0;
- vb->state = VIDEOBUF_QUEUED;
+ if (vip->format.field == V4L2_FIELD_INTERLACED)
+ offset = vip->format.width * 2;
- if (vip->active) {
- list_add_tail(&vb->queue, &vip->capture);
+ spin_lock_irq(&vip->slock);
+ /* Enable acquisition */
+ reg_write(vip, DVP_CTL, reg_read(vip, DVP_CTL) | DVP_CTL_ENA);
+ /* Set Top and Bottom Field memory address */
+ reg_write(vip, DVP_VTP, (u32)vip_buf->dma);
+ reg_write(vip, DVP_VBP, (u32)vip_buf->dma + offset);
+ spin_unlock_irq(&vip->slock);
+}
+
+/* Fetch the next buffer to activate */
+static void vip_active_buf_next(struct sta2x11_vip *vip)
+{
+ /* Get the next buffer */
+ spin_lock(&vip->lock);
+ if (list_empty(&vip->buffer_list)) {/* No available buffer */
+ spin_unlock(&vip->lock);
return;
}
-
- vip->started = 1;
+ vip->active = list_first_entry(&vip->buffer_list,
+ struct vip_buffer,
+ list);
+ /* Reset Top and Bottom counter */
vip->tcount = 0;
vip->bcount = 0;
- vip->active = vb;
- vb->state = VIDEOBUF_ACTIVE;
+ spin_unlock(&vip->lock);
+ if (vb2_is_streaming(&vip->vb_vidq)) { /* streaming is on */
+ start_dma(vip, vip->active); /* start dma capture */
+ }
+}
- dma = videobuf_to_dma_contig(vb);
- REG_WRITE(vip, DVP_TFO, (0 << 16) | (0));
- /* despite of interlace mode, upper and lower frames start at zero */
- REG_WRITE(vip, DVP_BFO, (0 << 16) | (0));
+/* Videobuf2 Operations */
+static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], void *alloc_ctxs[])
+{
+ struct sta2x11_vip *vip = vb2_get_drv_priv(vq);
- switch (vip->format.field) {
- case V4L2_FIELD_INTERLACED:
- REG_WRITE(vip, DVP_TFS,
- ((vip->format.height / 2 - 1) << 16) |
- (2 * vip->format.width - 1));
- REG_WRITE(vip, DVP_BFS, ((vip->format.height / 2 - 1) << 16) |
- (2 * vip->format.width - 1));
- REG_WRITE(vip, DVP_VTP, dma);
- REG_WRITE(vip, DVP_VBP, dma + vip->format.width * 2);
- REG_WRITE(vip, DVP_VMP, 4 * vip->format.width);
- break;
- case V4L2_FIELD_TOP:
- REG_WRITE(vip, DVP_TFS,
- ((vip->format.height - 1) << 16) |
- (2 * vip->format.width - 1));
- REG_WRITE(vip, DVP_BFS, ((0) << 16) |
- (2 * vip->format.width - 1));
- REG_WRITE(vip, DVP_VTP, dma);
- REG_WRITE(vip, DVP_VBP, dma);
- REG_WRITE(vip, DVP_VMP, 2 * vip->format.width);
- break;
- case V4L2_FIELD_BOTTOM:
- REG_WRITE(vip, DVP_TFS, ((0) << 16) |
- (2 * vip->format.width - 1));
- REG_WRITE(vip, DVP_BFS,
- ((vip->format.height) << 16) |
- (2 * vip->format.width - 1));
- REG_WRITE(vip, DVP_VTP, dma);
- REG_WRITE(vip, DVP_VBP, dma);
- REG_WRITE(vip, DVP_VMP, 2 * vip->format.width);
- break;
+ if (!(*nbuffers) || *nbuffers < MAX_FRAMES)
+ *nbuffers = MAX_FRAMES;
- default:
- pr_warning("VIP: unknown field format\n");
- return;
- }
+ *nplanes = 1;
+ sizes[0] = vip->format.sizeimage;
+ alloc_ctxs[0] = vip->alloc_ctx;
- REG_WRITE(vip, DVP_CTL, DVP_CTL_ENA);
-}
+ vip->sequence = 0;
+ vip->active = NULL;
+ vip->tcount = 0;
+ vip->bcount = 0;
-/**
- * buff_release - release buffer
- * @vq: queue in videobuf layer
- * @vb: buffer to be released
- *
- * release buffer in videobuf layer
- */
-static void buf_release(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+ return 0;
+};
+static int buffer_init(struct vb2_buffer *vb)
{
+ struct vip_buffer *vip_buf = to_vip_buffer(vb);
- videobuf_dma_contig_free(vq, vb);
- vb->state = VIDEOBUF_NEEDS_INIT;
+ vip_buf->dma = (dma_addr_t)vb2_plane_cookie(vb, 0);
+ INIT_LIST_HEAD(&vip_buf->list);
+ return 0;
}
-static struct videobuf_queue_ops vip_qops = {
- .buf_setup = buf_setup,
- .buf_prepare = buf_prepare,
- .buf_queue = buf_queue,
- .buf_release = buf_release,
-};
-
-/**
- * vip_open - open video device
- * @file: descriptor of device
- *
- * open device, make sure it is only opened once.
- * return value: 0, no error.
- *
- * -EBUSY, device is already opened
- *
- * -ENOMEM, no memory for auxiliary DMA buffer
- */
-static int vip_open(struct file *file)
+static int buffer_prepare(struct vb2_buffer *vb)
{
- struct video_device *dev = video_devdata(file);
- struct sta2x11_vip *vip = video_get_drvdata(dev);
+ struct sta2x11_vip *vip = vb2_get_drv_priv(vb->vb2_queue);
+ struct vip_buffer *vip_buf = to_vip_buffer(vb);
+ unsigned long size;
+
+ size = vip->format.sizeimage;
+ if (vb2_plane_size(vb, 0) < size) {
+ v4l2_err(&vip->v4l2_dev, "buffer too small (%lu < %lu)\n",
+ vb2_plane_size(vb, 0), size);
+ return -EINVAL;
+ }
- mutex_lock(&vip->mutex);
- vip->users++;
+ vb2_set_plane_payload(&vip_buf->vb, 0, size);
- if (vip->users > 1) {
- vip->users--;
- mutex_unlock(&vip->mutex);
- return -EBUSY;
+ return 0;
+}
+static void buffer_queue(struct vb2_buffer *vb)
+{
+ struct sta2x11_vip *vip = vb2_get_drv_priv(vb->vb2_queue);
+ struct vip_buffer *vip_buf = to_vip_buffer(vb);
+ unsigned long size;
+
+ size = vip->format.sizeimage;
+ dma_sync_single_for_device(&vip->pdev->dev, vip_buf->dma,
+ size, DMA_FROM_DEVICE);
+ spin_lock(&vip->lock);
+ list_add_tail(&vip_buf->list, &vip->buffer_list);
+ if (!vip->active) { /* No active buffer, active the first one */
+ vip->active = list_first_entry(&vip->buffer_list,
+ struct vip_buffer,
+ list);
+ if (vb2_is_streaming(&vip->vb_vidq)) /* streaming is on */
+ start_dma(vip, vip_buf); /* start dma capture */
}
+ spin_unlock(&vip->lock);
+}
+static int buffer_finish(struct vb2_buffer *vb)
+{
+ struct sta2x11_vip *vip = vb2_get_drv_priv(vb->vb2_queue);
+ struct vip_buffer *vip_buf = to_vip_buffer(vb);
+ unsigned long size;
- file->private_data = dev;
- vip->overflow = 0;
- vip->started = 0;
- vip->closing = 0;
- vip->active = NULL;
+ /* Buffer handled, remove it from the list */
+ spin_lock(&vip->lock);
+ list_del_init(&vip_buf->list);
+ spin_unlock(&vip->lock);
+ /* DMA sync */
+ size = vip->format.sizeimage;
+ dma_sync_single_for_cpu(&vip->pdev->dev, vip_buf->dma,
+ size, DMA_FROM_DEVICE);
- INIT_LIST_HEAD(&vip->capture);
- vip->mem_spare = dma_alloc_coherent(&vip->pdev->dev, 64,
- &vip->dma_spare, GFP_KERNEL);
- if (!vip->mem_spare) {
- vip->users--;
- mutex_unlock(&vip->mutex);
- return -ENOMEM;
- }
+ vip_active_buf_next(vip);
- mutex_unlock(&vip->mutex);
- videobuf_queue_dma_contig_init_cached(&vip->vb_vidq,
- &vip_qops,
- &vip->pdev->dev,
- &vip->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_INTERLACED,
- sizeof(struct videobuf_buffer),
- vip, NULL);
- REG_READ(vip, DVP_ITS);
- REG_WRITE(vip, DVP_HLFLN, DVP_HLFLN_SD);
- REG_WRITE(vip, DVP_ITM, DVP_IT_VSB | DVP_IT_VST);
- REG_WRITE(vip, DVP_CTL, DVP_CTL_RST);
- REG_WRITE(vip, DVP_CTL, 0);
- REG_READ(vip, DVP_ITS);
return 0;
}
-/**
- * vip_close - close video device
- * @file: descriptor of device
- *
- * close video device, wait until all pending operations are finished
- * ( maximum FRAME_MAX buffers pending )
- * Turn off interrupts.
- *
- * return value: 0, always succesful.
- */
-static int vip_close(struct file *file)
+static int start_streaming(struct vb2_queue *vq, unsigned int count)
{
- struct video_device *dev = video_devdata(file);
- struct sta2x11_vip *vip = video_get_drvdata(dev);
+ struct sta2x11_vip *vip = vb2_get_drv_priv(vq);
- vip->closing = 1;
- if (vip->active)
- videobuf_waiton(&vip->vb_vidq, vip->active, 0, 0);
spin_lock_irq(&vip->slock);
-
- REG_WRITE(vip, DVP_ITM, 0);
- REG_WRITE(vip, DVP_CTL, DVP_CTL_RST);
- REG_WRITE(vip, DVP_CTL, 0);
- REG_READ(vip, DVP_ITS);
-
- vip->started = 0;
- vip->active = NULL;
-
+ /* Enable interrupt VSYNC Top and Bottom*/
+ reg_write(vip, DVP_ITM, DVP_IT_VSB | DVP_IT_VST);
spin_unlock_irq(&vip->slock);
- videobuf_stop(&vip->vb_vidq);
- videobuf_mmap_free(&vip->vb_vidq);
+ if (count)
+ start_dma(vip, vip->active);
- dma_free_coherent(&vip->pdev->dev, 64, vip->mem_spare, vip->dma_spare);
- file->private_data = NULL;
- mutex_lock(&vip->mutex);
- vip->users--;
- mutex_unlock(&vip->mutex);
return 0;
}
-/**
- * vip_read - read from video input
- * @file: descriptor of device
- * @data: user buffer
- * @count: number of bytes to be read
- * @ppos: position within stream
- *
- * read video data from video device.
- * handling is done in generic videobuf layer
- * return value: provided by videobuf layer
- */
-static ssize_t vip_read(struct file *file, char __user *data,
- size_t count, loff_t *ppos)
+/* abort streaming and wait for last buffer */
+static int stop_streaming(struct vb2_queue *vq)
{
- struct video_device *dev = file->private_data;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
-
- return videobuf_read_stream(&vip->vb_vidq, data, count, ppos, 0,
- file->f_flags & O_NONBLOCK);
+ struct sta2x11_vip *vip = vb2_get_drv_priv(vq);
+ struct vip_buffer *vip_buf, *node;
+
+ /* Disable acquisition */
+ reg_write(vip, DVP_CTL, reg_read(vip, DVP_CTL) & ~DVP_CTL_ENA);
+ /* Disable all interrupts */
+ reg_write(vip, DVP_ITM, 0);
+
+ /* Release all active buffers */
+ spin_lock(&vip->lock);
+ list_for_each_entry_safe(vip_buf, node, &vip->buffer_list, list) {
+ vb2_buffer_done(&vip_buf->vb, VB2_BUF_STATE_ERROR);
+ list_del(&vip_buf->list);
+ }
+ spin_unlock(&vip->lock);
+ return 0;
}
-/**
- * vip_mmap - map user buffer
- * @file: descriptor of device
- * @vma: user buffer
- *
- * map user space buffer into kernel mode, including DMA address.
- * handling is done in generic videobuf layer.
- * return value: provided by videobuf layer
- */
-static int vip_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct video_device *dev = file->private_data;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
+static struct vb2_ops vip_video_qops = {
+ .queue_setup = queue_setup,
+ .buf_init = buffer_init,
+ .buf_prepare = buffer_prepare,
+ .buf_finish = buffer_finish,
+ .buf_queue = buffer_queue,
+ .start_streaming = start_streaming,
+ .stop_streaming = stop_streaming,
+};
- return videobuf_mmap_mapper(&vip->vb_vidq, vma);
-}
-/**
- * vip_poll - poll for event
- * @file: descriptor of device
- * @wait: contains events to be waited for
- *
- * wait for event related to video device.
- * handling is done in generic videobuf layer.
- * return value: provided by videobuf layer
- */
-static unsigned int vip_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct video_device *dev = file->private_data;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
+/* File Operations */
+static const struct v4l2_file_operations vip_fops = {
+ .owner = THIS_MODULE,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
+ .unlocked_ioctl = video_ioctl2,
+ .read = vb2_fop_read,
+ .mmap = vb2_fop_mmap,
+ .poll = vb2_fop_poll
+};
- return videobuf_poll_stream(file, &vip->vb_vidq, wait);
-}
-/**
- * vidioc_querycap - return capabilities of device
- * @file: descriptor of device (not used)
- * @priv: points to current videodevice
- * @cap: contains return values
- *
- * the capabilities of the device are returned
- *
- * return value: 0, no error.
- */
+/* V4L2 ioctl Operations */
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
+ struct sta2x11_vip *vip = video_drvdata(file);
- memset(cap, 0, sizeof(struct v4l2_capability));
- strcpy(cap->driver, DRV_NAME);
- strcpy(cap->card, DRV_NAME);
- cap->version = 0;
+ strcpy(cap->driver, KBUILD_MODNAME);
+ strcpy(cap->card, KBUILD_MODNAME);
snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
pci_name(vip->pdev));
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING;
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
-/**
- * vidioc_s_std - set video standard
- * @file: descriptor of device (not used)
- * @priv: points to current videodevice
- * @std: contains standard to be set
- *
- * the video standard is set
- *
- * return value: 0, no error.
- *
- * -EIO, no input signal detected
- *
- * other, returned from video DAC.
- */
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *std)
{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
+ struct sta2x11_vip *vip = video_drvdata(file);
v4l2_std_id oldstd = vip->std, newstd;
int status;
@@ -590,110 +432,22 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *std)
return v4l2_subdev_call(vip->decoder, core, s_std, *std);
}
-/**
- * vidioc_g_std - get video standard
- * @file: descriptor of device (not used)
- * @priv: points to current videodevice
- * @std: contains return values
- *
- * the current video standard is returned
- *
- * return value: 0, no error.
- */
static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std)
{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
+ struct sta2x11_vip *vip = video_drvdata(file);
*std = vip->std;
return 0;
}
-/**
- * vidioc_querystd - get possible video standards
- * @file: descriptor of device (not used)
- * @priv: points to current videodevice
- * @std: contains return values
- *
- * all possible video standards are returned
- *
- * return value: delivered by video DAC routine.
- */
static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *std)
{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
+ struct sta2x11_vip *vip = video_drvdata(file);
return v4l2_subdev_call(vip->decoder, video, querystd, std);
}
-/**
- * vidioc_queryctl - get possible control settings
- * @file: descriptor of device (not used)
- * @priv: points to current videodevice
- * @ctrl: contains return values
- *
- * return possible values for a control
- * return value: delivered by video DAC routine.
- */
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *ctrl)
-{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
-
- return v4l2_subdev_call(vip->decoder, core, queryctrl, ctrl);
-}
-
-/**
- * vidioc_g_ctl - get control value
- * @file: descriptor of device (not used)
- * @priv: points to current videodevice
- * @ctrl: contains return values
- *
- * return setting for a control value
- * return value: delivered by video DAC routine.
- */
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
-
- return v4l2_subdev_call(vip->decoder, core, g_ctrl, ctrl);
-}
-
-/**
- * vidioc_s_ctl - set control value
- * @file: descriptor of device (not used)
- * @priv: points to current videodevice
- * @ctrl: contains value to be set
- *
- * set value for a specific control
- * return value: delivered by video DAC routine.
- */
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
-
- return v4l2_subdev_call(vip->decoder, core, s_ctrl, ctrl);
-}
-
-/**
- * vidioc_enum_input - return name of input line
- * @file: descriptor of device (not used)
- * @priv: points to current videodevice
- * @inp: contains return values
- *
- * the user friendly name of the input line is returned
- *
- * return value: 0, no error.
- *
- * -EINVAL, input line number out of range
- */
static int vidioc_enum_input(struct file *file, void *priv,
struct v4l2_input *inp)
{
@@ -707,22 +461,9 @@ static int vidioc_enum_input(struct file *file, void *priv,
return 0;
}
-/**
- * vidioc_s_input - set input line
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
- * @i: new input line number
- *
- * the current active input line is set
- *
- * return value: 0, no error.
- *
- * -EINVAL, line number out of range
- */
static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
+ struct sta2x11_vip *vip = video_drvdata(file);
int ret;
if (i > 1)
@@ -735,36 +476,14 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
return 0;
}
-/**
- * vidioc_g_input - return input line
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
- * @i: returned input line number
- *
- * the current active input line is returned
- *
- * return value: always 0.
- */
static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
+ struct sta2x11_vip *vip = video_drvdata(file);
*i = vip->input;
return 0;
}
-/**
- * vidioc_enum_fmt_vid_cap - return video capture format
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
- * @f: returned format information
- *
- * returns name and format of video capture
- * Only UYVY is supported by hardware.
- *
- * return value: always 0.
- */
static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
@@ -778,32 +497,12 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
-/**
- * vidioc_try_fmt_vid_cap - set video capture format
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
- * @f: new format
- *
- * new video format is set which includes width and
- * field type. width is fixed to 720, no scaling.
- * Only UYVY is supported by this hardware.
- * the minimum height is 200, the maximum is 576 (PAL)
- *
- * return value: 0, no error
- *
- * -EINVAL, pixel or field format not supported
- *
- */
static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
+ struct sta2x11_vip *vip = video_drvdata(file);
int interlace_lim;
- if (V4L2_PIX_FMT_UYVY != f->fmt.pix.pixelformat)
- return -EINVAL;
-
if (V4L2_STD_525_60 & vip->std)
interlace_lim = 240;
else
@@ -827,6 +526,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
return -EINVAL;
}
+ /* It is the only supported format */
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
f->fmt.pix.height &= ~1;
if (2 * interlace_lim < f->fmt.pix.height)
f->fmt.pix.height = 2 * interlace_lim;
@@ -840,304 +541,222 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
-/**
- * vidioc_s_fmt_vid_cap - set current video format parameters
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
- * @f: returned format information
- *
- * set new capture format
- * return value: 0, no error
- *
- * other, delivered by video DAC routine.
- */
static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
+ struct sta2x11_vip *vip = video_drvdata(file);
+ unsigned int t_stop, b_stop, pitch;
int ret;
ret = vidioc_try_fmt_vid_cap(file, priv, f);
if (ret)
return ret;
+ if (vb2_is_busy(&vip->vb_vidq)) {
+ /* Can't change format during acquisition */
+ v4l2_err(&vip->v4l2_dev, "device busy\n");
+ return -EBUSY;
+ }
+
memcpy(&vip->format, &f->fmt.pix, sizeof(struct v4l2_pix_format));
+ switch (vip->format.field) {
+ case V4L2_FIELD_INTERLACED:
+ t_stop = ((vip->format.height / 2 - 1) << 16) |
+ (2 * vip->format.width - 1);
+ b_stop = t_stop;
+ pitch = 4 * vip->format.width;
+ break;
+ case V4L2_FIELD_TOP:
+ t_stop = ((vip->format.height - 1) << 16) |
+ (2 * vip->format.width - 1);
+ b_stop = (0 << 16) | (2 * vip->format.width - 1);
+ pitch = 2 * vip->format.width;
+ break;
+ case V4L2_FIELD_BOTTOM:
+ t_stop = (0 << 16) | (2 * vip->format.width - 1);
+ b_stop = (vip->format.height << 16) |
+ (2 * vip->format.width - 1);
+ pitch = 2 * vip->format.width;
+ break;
+ default:
+ v4l2_err(&vip->v4l2_dev, "unknown field format\n");
+ return -EINVAL;
+ }
+
+ spin_lock_irq(&vip->slock);
+ /* Y-X Top Field Offset */
+ reg_write(vip, DVP_TFO, 0);
+ /* Y-X Bottom Field Offset */
+ reg_write(vip, DVP_BFO, 0);
+ /* Y-X Top Field Stop*/
+ reg_write(vip, DVP_TFS, t_stop);
+ /* Y-X Bottom Field Stop */
+ reg_write(vip, DVP_BFS, b_stop);
+ /* Video Memory Pitch */
+ reg_write(vip, DVP_VMP, pitch);
+ spin_unlock_irq(&vip->slock);
+
return 0;
}
-/**
- * vidioc_g_fmt_vid_cap - get current video format parameters
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
- * @f: contains format information
- *
- * returns current video format parameters
- *
- * return value: 0, always successful
- */
static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
+ struct sta2x11_vip *vip = video_drvdata(file);
memcpy(&f->fmt.pix, &vip->format, sizeof(struct v4l2_pix_format));
return 0;
}
-/**
- * vidioc_reqfs - request buffer
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
- * @p: video buffer
- *
- * Handling is done in generic videobuf layer.
- */
-static int vidioc_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *p)
-{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
-
- return videobuf_reqbufs(&vip->vb_vidq, p);
-}
-
-/**
- * vidioc_querybuf - query buffer
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
- * @p: video buffer
- *
- * query buffer state.
- * Handling is done in generic videobuf layer.
- */
-static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
-
- return videobuf_querybuf(&vip->vb_vidq, p);
-}
-
-/**
- * vidioc_qbuf - queue a buffer
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
- * @p: video buffer
- *
- * Handling is done in generic videobuf layer.
- */
-static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
-
- return videobuf_qbuf(&vip->vb_vidq, p);
-}
-
-/**
- * vidioc_dqbuf - dequeue a buffer
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
- * @p: video buffer
- *
- * Handling is done in generic videobuf layer.
- */
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
-
- return videobuf_dqbuf(&vip->vb_vidq, p, file->f_flags & O_NONBLOCK);
-}
-
-/**
- * vidioc_streamon - turn on streaming
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
- * @type: type of capture
- *
- * turn on streaming.
- * Handling is done in generic videobuf layer.
- */
-static int vidioc_streamon(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
-
- return videobuf_streamon(&vip->vb_vidq);
-}
-
-/**
- * vidioc_streamoff - turn off streaming
- * @file: descriptor of device ( not used)
- * @priv: points to current videodevice
- * @type: type of capture
- *
- * turn off streaming.
- * Handling is done in generic videobuf layer.
- */
-static int vidioc_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct video_device *dev = priv;
- struct sta2x11_vip *vip = video_get_drvdata(dev);
-
- return videobuf_streamoff(&vip->vb_vidq);
-}
-
-static const struct v4l2_file_operations vip_fops = {
- .owner = THIS_MODULE,
- .open = vip_open,
- .release = vip_close,
- .ioctl = video_ioctl2,
- .read = vip_read,
- .mmap = vip_mmap,
- .poll = vip_poll
-};
-
static const struct v4l2_ioctl_ops vip_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
- .vidioc_s_std = vidioc_s_std,
+ /* FMT handling */
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+ /* Buffer handlers */
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ /* Stream on/off */
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+ /* Standard handling */
.vidioc_g_std = vidioc_g_std,
+ .vidioc_s_std = vidioc_s_std,
.vidioc_querystd = vidioc_querystd,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
+ /* Input handling */
.vidioc_enum_input = vidioc_enum_input,
- .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
- .vidioc_s_input = vidioc_s_input,
.vidioc_g_input = vidioc_g_input,
- .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
- .vidioc_reqbufs = vidioc_reqbufs,
- .vidioc_querybuf = vidioc_querybuf,
- .vidioc_qbuf = vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_s_input = vidioc_s_input,
+ /* Log status ioctl */
+ .vidioc_log_status = v4l2_ctrl_log_status,
+ /* Event handling */
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
static struct video_device video_dev_template = {
- .name = DRV_NAME,
+ .name = KBUILD_MODNAME,
.release = video_device_release,
.fops = &vip_fops,
.ioctl_ops = &vip_ioctl_ops,
.tvnorms = V4L2_STD_ALL,
};
-/**
- * vip_irq - interrupt routine
- * @irq: Number of interrupt ( not used, correct number is assumed )
- * @vip: local data structure containing all information
- *
- * check for both frame interrupts set ( top and bottom ).
- * check FIFO overflow, but limit number of log messages after open.
- * signal a complete buffer if done.
- * dequeue a new buffer if available.
- * disable VIP if no buffer available.
- *
- * return value: IRQ_NONE, interrupt was not generated by VIP
- *
- * IRQ_HANDLED, interrupt done.
- */
+
static irqreturn_t vip_irq(int irq, struct sta2x11_vip *vip)
{
- u32 status, dma;
- unsigned long flags;
- struct videobuf_buffer *vb;
+ unsigned int status;
- status = REG_READ(vip, DVP_ITS);
+ status = reg_read(vip, DVP_ITS);
- if (!status) {
- pr_debug("VIP: irq ignored\n");
+ if (!status) /* No interrupt to handle */
return IRQ_NONE;
- }
- if (!vip->started)
- return IRQ_HANDLED;
-
- if (status & DVP_IT_VSB)
- vip->bcount++;
-
- if (status & DVP_IT_VST)
- vip->tcount++;
+ if (status & DVP_IT_FIFO)
+ if (vip->overflow++ > 5)
+ pr_info("VIP: fifo overflow\n");
- if ((DVP_IT_VSB | DVP_IT_VST) == (status & (DVP_IT_VST | DVP_IT_VSB))) {
+ if ((status & DVP_IT_VST) && (status & DVP_IT_VSB)) {
/* this is bad, we are too slow, hope the condition is gone
* on the next frame */
- pr_info("VIP: both irqs\n");
return IRQ_HANDLED;
}
- if (status & DVP_IT_FIFO) {
- if (5 > vip->overflow++)
- pr_info("VIP: fifo overflow\n");
- }
-
- if (2 > vip->tcount)
+ if (status & DVP_IT_VST)
+ if ((++vip->tcount) < 2)
+ return IRQ_HANDLED;
+ if (status & DVP_IT_VSB) {
+ vip->bcount++;
return IRQ_HANDLED;
+ }
- if (status & DVP_IT_VSB)
- return IRQ_HANDLED;
+ if (vip->active) { /* Acquisition is over on this buffer */
+ /* Disable acquisition */
+ reg_write(vip, DVP_CTL, reg_read(vip, DVP_CTL) & ~DVP_CTL_ENA);
+ /* Remove the active buffer from the list */
+ do_gettimeofday(&vip->active->vb.v4l2_buf.timestamp);
+ vip->active->vb.v4l2_buf.sequence = vip->sequence++;
+ vb2_buffer_done(&vip->active->vb, VB2_BUF_STATE_DONE);
+ }
- spin_lock_irqsave(&vip->slock, flags);
+ return IRQ_HANDLED;
+}
- REG_WRITE(vip, DVP_CTL, REG_READ(vip, DVP_CTL) & ~DVP_CTL_ENA);
- if (vip->active) {
- do_gettimeofday(&vip->active->ts);
- vip->active->field_count++;
- vip->active->state = VIDEOBUF_DONE;
- wake_up(&vip->active->done);
- vip->active = NULL;
+static void sta2x11_vip_init_register(struct sta2x11_vip *vip)
+{
+ /* Register initialization */
+ spin_lock_irq(&vip->slock);
+ /* Clean interrupt */
+ reg_read(vip, DVP_ITS);
+ /* Enable Half Line per vertical */
+ reg_write(vip, DVP_HLFLN, DVP_HLFLN_SD);
+ /* Reset VIP control */
+ reg_write(vip, DVP_CTL, DVP_CTL_RST);
+ /* Clear VIP control */
+ reg_write(vip, DVP_CTL, 0);
+ spin_unlock_irq(&vip->slock);
+}
+static void sta2x11_vip_clear_register(struct sta2x11_vip *vip)
+{
+ spin_lock_irq(&vip->slock);
+ /* Disable interrupt */
+ reg_write(vip, DVP_ITM, 0);
+ /* Reset VIP Control */
+ reg_write(vip, DVP_CTL, DVP_CTL_RST);
+ /* Clear VIP Control */
+ reg_write(vip, DVP_CTL, 0);
+ /* Clean VIP Interrupt */
+ reg_read(vip, DVP_ITS);
+ spin_unlock_irq(&vip->slock);
+}
+static int sta2x11_vip_init_buffer(struct sta2x11_vip *vip)
+{
+ memset(&vip->vb_vidq, 0, sizeof(struct vb2_queue));
+ vip->vb_vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ vip->vb_vidq.io_modes = VB2_MMAP | VB2_READ;
+ vip->vb_vidq.drv_priv = vip;
+ vip->vb_vidq.buf_struct_size = sizeof(struct vip_buffer);
+ vip->vb_vidq.ops = &vip_video_qops;
+ vip->vb_vidq.mem_ops = &vb2_dma_streaming_memops;
+ vb2_queue_init(&vip->vb_vidq);
+ INIT_LIST_HEAD(&vip->buffer_list);
+ spin_lock_init(&vip->lock);
+
+ vip->alloc_ctx = vb2_dma_streaming_init_ctx(&vip->pdev->dev);
+ if (IS_ERR(vip->alloc_ctx)) {
+ v4l2_err(&vip->v4l2_dev, "Can't allocate buffer context");
+ return PTR_ERR(vip->alloc_ctx);
}
- if (!vip->closing) {
- if (list_empty(&vip->capture))
- goto done;
-
- vb = list_first_entry(&vip->capture, struct videobuf_buffer,
- queue);
- if (NULL == vb) {
- pr_info("VIP: no buffer\n");
- goto done;
- }
- vb->state = VIDEOBUF_ACTIVE;
- list_del(&vb->queue);
- vip->active = vb;
- dma = videobuf_to_dma_contig(vb);
- switch (vip->format.field) {
- case V4L2_FIELD_INTERLACED:
- REG_WRITE(vip, DVP_VTP, dma);
- REG_WRITE(vip, DVP_VBP, dma + vip->format.width * 2);
- break;
- case V4L2_FIELD_TOP:
- case V4L2_FIELD_BOTTOM:
- REG_WRITE(vip, DVP_VTP, dma);
- REG_WRITE(vip, DVP_VBP, dma);
- break;
- default:
- pr_warning("VIP: unknown field format\n");
- goto done;
- break;
- }
- REG_WRITE(vip, DVP_CTL, REG_READ(vip, DVP_CTL) | DVP_CTL_ENA);
+ return 0;
+}
+static void sta2x11_vip_release_buffer(struct sta2x11_vip *vip)
+{
+ vb2_dma_streaming_cleanup_ctx(vip->alloc_ctx);
+}
+static int sta2x11_vip_init_controls(struct sta2x11_vip *vip)
+{
+ /*
+ * Inititialize an empty control so VIP can inerithing controls
+ * from ADV7180
+ */
+ v4l2_ctrl_handler_init(&vip->ctrl_hdl, 0);
+
+ vip->v4l2_dev.ctrl_handler = &vip->ctrl_hdl;
+ if (vip->ctrl_hdl.error) {
+ int err = vip->ctrl_hdl.error;
+
+ v4l2_ctrl_handler_free(&vip->ctrl_hdl);
+ return err;
}
-done:
- spin_unlock_irqrestore(&vip->slock, flags);
- return IRQ_HANDLED;
+
+ return 0;
}
-/**
- * vip_gpio_reserve - reserve gpio pin
- * @dev: device
- * @pin: GPIO pin number
- * @dir: direction, input or output
- * @name: GPIO pin name
- *
- */
static int vip_gpio_reserve(struct device *dev, int pin, int dir,
const char *name)
{
@@ -1170,13 +789,6 @@ static int vip_gpio_reserve(struct device *dev, int pin, int dir,
return 0;
}
-/**
- * vip_gpio_release - release gpio pin
- * @dev: device
- * @pin: GPIO pin number
- * @name: GPIO pin name
- *
- */
static void vip_gpio_release(struct device *dev, int pin, const char *name)
{
if (pin != -1) {
@@ -1186,25 +798,6 @@ static void vip_gpio_release(struct device *dev, int pin, const char *name)
}
}
-/**
- * sta2x11_vip_init_one - init one instance of video device
- * @pdev: PCI device
- * @ent: (not used)
- *
- * allocate reset pins for DAC.
- * Reset video DAC, this is done via reset line.
- * allocate memory for managing device
- * request interrupt
- * map IO region
- * register device
- * find and initialize video DAC
- *
- * return value: 0, no error
- *
- * -ENOMEM, no memory
- *
- * -ENODEV, device could not be detected or registered
- */
static int __devinit sta2x11_vip_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -1212,10 +805,17 @@ static int __devinit sta2x11_vip_init_one(struct pci_dev *pdev,
struct sta2x11_vip *vip;
struct vip_config *config;
+ /* Check if hardware support 26-bit DMA */
+ if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(26))) {
+ dev_err(&pdev->dev, "26-bit DMA addressing not available\n");
+ return -EINVAL;
+ }
+ /* Enable PCI */
ret = pci_enable_device(pdev);
if (ret)
return ret;
+ /* Get VIP platform data */
config = dev_get_platdata(&pdev->dev);
if (!config) {
dev_info(&pdev->dev, "VIP slot disabled\n");
@@ -1223,6 +823,7 @@ static int __devinit sta2x11_vip_init_one(struct pci_dev *pdev,
goto disable;
}
+ /* Power configuration */
ret = vip_gpio_reserve(&pdev->dev, config->pwr_pin, 0,
config->pwr_name);
if (ret)
@@ -1237,7 +838,6 @@ static int __devinit sta2x11_vip_init_one(struct pci_dev *pdev,
goto disable;
}
}
-
if (config->pwr_pin != -1) {
/* Datasheet says 5ms between PWR and RST */
usleep_range(5000, 25000);
@@ -1251,17 +851,20 @@ static int __devinit sta2x11_vip_init_one(struct pci_dev *pdev,
}
usleep_range(5000, 25000);
+ /* Allocate a new VIP instance */
vip = kzalloc(sizeof(struct sta2x11_vip), GFP_KERNEL);
if (!vip) {
ret = -ENOMEM;
goto release_gpios;
}
-
vip->pdev = pdev;
vip->std = V4L2_STD_PAL;
vip->format = formats_50[0];
vip->config = config;
+ ret = sta2x11_vip_init_controls(vip);
+ if (ret)
+ goto free_mem;
if (v4l2_device_register(&pdev->dev, &vip->v4l2_dev))
goto free_mem;
@@ -1271,46 +874,52 @@ static int __devinit sta2x11_vip_init_one(struct pci_dev *pdev,
pci_set_master(pdev);
- ret = pci_request_regions(pdev, DRV_NAME);
+ ret = pci_request_regions(pdev, KBUILD_MODNAME);
if (ret)
goto unreg;
vip->iomem = pci_iomap(pdev, 0, 0x100);
if (!vip->iomem) {
- ret = -ENOMEM; /* FIXME */
+ ret = -ENOMEM;
goto release;
}
pci_enable_msi(pdev);
- INIT_LIST_HEAD(&vip->capture);
+ /* Initialize buffer */
+ ret = sta2x11_vip_init_buffer(vip);
+ if (ret)
+ goto unmap;
+
spin_lock_init(&vip->slock);
- mutex_init(&vip->mutex);
- vip->started = 0;
- vip->disabled = 0;
ret = request_irq(pdev->irq,
(irq_handler_t) vip_irq,
- IRQF_SHARED, DRV_NAME, vip);
+ IRQF_SHARED, KBUILD_MODNAME, vip);
if (ret) {
dev_err(&pdev->dev, "request_irq failed\n");
ret = -ENODEV;
- goto unmap;
+ goto release_buf;
}
+ /* Alloc, initialize and register video device */
vip->video_dev = video_device_alloc();
if (!vip->video_dev) {
ret = -ENOMEM;
goto release_irq;
}
- *(vip->video_dev) = video_dev_template;
+ vip->video_dev = &video_dev_template;
+ vip->video_dev->v4l2_dev = &vip->v4l2_dev;
+ vip->video_dev->queue = &vip->vb_vidq;
+ vip->video_dev->flags |= V4L2_FL_USES_V4L2_FH | V4L2_FL_USE_FH_PRIO;
video_set_drvdata(vip->video_dev, vip);
ret = video_register_device(vip->video_dev, VFL_TYPE_GRABBER, -1);
if (ret)
goto vrelease;
+ /* Get ADV7180 subdevice */
vip->adapter = i2c_get_adapter(vip->config->i2c_id);
if (!vip->adapter) {
ret = -ENODEV;
@@ -1328,10 +937,11 @@ static int __devinit sta2x11_vip_init_one(struct pci_dev *pdev,
}
i2c_put_adapter(vip->adapter);
-
v4l2_subdev_call(vip->decoder, core, init, 0);
- pr_info("STA2X11 Video Input Port (VIP) loaded\n");
+ sta2x11_vip_init_register(vip);
+
+ dev_info(&pdev->dev, "STA2X11 Video Input Port (VIP) loaded\n");
return 0;
vunreg:
@@ -1343,10 +953,12 @@ vrelease:
video_device_release(vip->video_dev);
release_irq:
free_irq(pdev->irq, vip);
+release_buf:
+ sta2x11_vip_release_buffer(vip);
pci_disable_msi(pdev);
unmap:
+ vb2_queue_release(&vip->vb_vidq);
pci_iounmap(pdev, vip->iomem);
- mutex_destroy(&vip->mutex);
release:
pci_release_regions(pdev);
unreg:
@@ -1364,34 +976,24 @@ disable:
return ret;
}
-/**
- * sta2x11_vip_remove_one - release device
- * @pdev: PCI device
- *
- * Undo everything done in .._init_one
- *
- * unregister video device
- * free interrupt
- * unmap ioadresses
- * free memory
- * free GPIO pins
- */
static void __devexit sta2x11_vip_remove_one(struct pci_dev *pdev)
{
struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
struct sta2x11_vip *vip =
container_of(v4l2_dev, struct sta2x11_vip, v4l2_dev);
+ sta2x11_vip_clear_register(vip);
+
video_set_drvdata(vip->video_dev, NULL);
video_unregister_device(vip->video_dev);
/*do not call video_device_release() here, is already done */
free_irq(pdev->irq, vip);
pci_disable_msi(pdev);
+ vb2_queue_release(&vip->vb_vidq);
pci_iounmap(pdev, vip->iomem);
pci_release_regions(pdev);
v4l2_device_unregister(&vip->v4l2_dev);
- mutex_destroy(&vip->mutex);
vip_gpio_release(&pdev->dev, vip->config->pwr_pin,
vip->config->pwr_name);
@@ -1407,18 +1009,12 @@ static void __devexit sta2x11_vip_remove_one(struct pci_dev *pdev)
#ifdef CONFIG_PM
-/**
- * sta2x11_vip_suspend - set device into power save mode
- * @pdev: PCI device
- * @state: new state of device
+/*
*
* all relevant registers are saved and an attempt to set a new state is made.
*
* return value: 0 always indicate success,
* even if device could not be disabled. (workaround for hardware problem)
- *
- * reurn value : 0, always succesful, even if hardware does not not support
- * power down mode.
*/
static int sta2x11_vip_suspend(struct pci_dev *pdev, pm_message_t state)
{
@@ -1429,15 +1025,15 @@ static int sta2x11_vip_suspend(struct pci_dev *pdev, pm_message_t state)
int i;
spin_lock_irqsave(&vip->slock, flags);
- vip->register_save_area[0] = REG_READ(vip, DVP_CTL);
- REG_WRITE(vip, DVP_CTL, vip->register_save_area[0] & DVP_CTL_DIS);
- vip->register_save_area[SAVE_COUNT] = REG_READ(vip, DVP_ITM);
- REG_WRITE(vip, DVP_ITM, 0);
+ vip->register_save_area[0] = reg_read(vip, DVP_CTL);
+ reg_write(vip, DVP_CTL, vip->register_save_area[0] & DVP_CTL_DIS);
+ vip->register_save_area[SAVE_COUNT] = reg_read(vip, DVP_ITM);
+ reg_write(vip, DVP_ITM, 0);
for (i = 1; i < SAVE_COUNT; i++)
- vip->register_save_area[i] = REG_READ(vip, 4 * i);
+ vip->register_save_area[i] = reg_read(vip, 4 * i);
for (i = 0; i < AUX_COUNT; i++)
vip->register_save_area[SAVE_COUNT + IRQ_COUNT + i] =
- REG_READ(vip, registers_to_save[i]);
+ reg_read(vip, registers_to_save[i]);
spin_unlock_irqrestore(&vip->slock, flags);
/* save pci state */
pci_save_state(pdev);
@@ -1453,16 +1049,9 @@ static int sta2x11_vip_suspend(struct pci_dev *pdev, pm_message_t state)
return 0;
}
-/**
- * sta2x11_vip_resume - resume device operation
- * @pdev : PCI device
- *
+/*
* re-enable device, set PCI state to powered and restore registers.
* resume normal device operation afterwards.
- *
- * return value: 0, no error.
- *
- * other, could not set device to power on state.
*/
static int sta2x11_vip_resume(struct pci_dev *pdev)
{
@@ -1497,12 +1086,12 @@ static int sta2x11_vip_resume(struct pci_dev *pdev)
spin_lock_irqsave(&vip->slock, flags);
for (i = 1; i < SAVE_COUNT; i++)
- REG_WRITE(vip, 4 * i, vip->register_save_area[i]);
+ reg_write(vip, 4 * i, vip->register_save_area[i]);
for (i = 0; i < AUX_COUNT; i++)
- REG_WRITE(vip, registers_to_save[i],
+ reg_write(vip, registers_to_save[i],
vip->register_save_area[SAVE_COUNT + IRQ_COUNT + i]);
- REG_WRITE(vip, DVP_CTL, vip->register_save_area[0]);
- REG_WRITE(vip, DVP_ITM, vip->register_save_area[SAVE_COUNT]);
+ reg_write(vip, DVP_CTL, vip->register_save_area[0]);
+ reg_write(vip, DVP_ITM, vip->register_save_area[SAVE_COUNT]);
spin_unlock_irqrestore(&vip->slock, flags);
return 0;
}
@@ -1515,7 +1104,7 @@ static DEFINE_PCI_DEVICE_TABLE(sta2x11_vip_pci_tbl) = {
};
static struct pci_driver sta2x11_vip_driver = {
- .name = DRV_NAME,
+ .name = KBUILD_MODNAME,
.probe = sta2x11_vip_init_one,
.remove = __devexit_p(sta2x11_vip_remove_one),
.id_table = sta2x11_vip_pci_tbl,
@@ -1543,7 +1132,7 @@ late_initcall_sync(sta2x11_vip_init_module);
#endif
MODULE_DESCRIPTION("STA2X11 Video Input Port driver");
-MODULE_AUTHOR("Wind River");
+MODULE_AUTHOR("Federico Vaga <federico.vaga@gmail.com>");
MODULE_LICENSE("GPL v2");
MODULE_SUPPORTED_DEVICE("sta2x11 video input");
MODULE_VERSION(DRV_VERSION);
--
1.7.11.2
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: Update VIP to videobuf2 and control framework
2012-08-06 7:36 ` Hans Verkuil
@ 2012-08-06 8:20 ` Federico Vaga
0 siblings, 0 replies; 22+ messages in thread
From: Federico Vaga @ 2012-08-06 8:20 UTC (permalink / raw)
To: Hans Verkuil
Cc: Mauro Carvalho Chehab, Pawel Osciak, Marek Szyprowski,
Hans Verkuil, Giancarlo Asnaghi, linux-media, linux-kernel,
Jonathan Corbet
> In that case I need to see your latest version of the source code to
> see why it doesn't work.
I send it as patch v2 of the previous one
--
Federico Vaga
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 3/3 v2] [media] sta2x11_vip: convert to videobuf2 and control framework
2012-08-06 8:17 ` [PATCH 3/3 v2] " Federico Vaga
@ 2012-08-06 8:42 ` Hans Verkuil
2012-08-06 8:55 ` Federico Vaga
0 siblings, 1 reply; 22+ messages in thread
From: Hans Verkuil @ 2012-08-06 8:42 UTC (permalink / raw)
To: Federico Vaga
Cc: Mauro Carvalho Chehab, Pawel Osciak, Marek Szyprowski,
Hans Verkuil, Giancarlo Asnaghi, linux-media, linux-kernel,
Jonathan Corbet
On Mon August 6 2012 10:17:39 Federico Vaga wrote:
> Signed-off-by: Federico Vaga <federico.vaga@gmail.com>
> Acked-by: Giancarlo Asnaghi <giancarlo.asnaghi@st.com>
>
> ---
> drivers/media/video/sta2x11_vip.c | 1239 +++++++++++++------------------------
> 1 file modificato, 414 inserzioni(+), 825 rimozioni(-)
>
> diff --git a/drivers/media/video/sta2x11_vip.c b/drivers/media/video/sta2x11_vip.c
> index 4c10205..ffd9f0a 100644
> --- a/drivers/media/video/sta2x11_vip.c
> +++ b/drivers/media/video/sta2x11_vip.c
> @@ -1186,25 +798,6 @@ static void vip_gpio_release(struct device *dev, int pin, const char *name)
> }
> }
>
> -/**
> - * sta2x11_vip_init_one - init one instance of video device
> - * @pdev: PCI device
> - * @ent: (not used)
> - *
> - * allocate reset pins for DAC.
> - * Reset video DAC, this is done via reset line.
> - * allocate memory for managing device
> - * request interrupt
> - * map IO region
> - * register device
> - * find and initialize video DAC
> - *
> - * return value: 0, no error
> - *
> - * -ENOMEM, no memory
> - *
> - * -ENODEV, device could not be detected or registered
> - */
> static int __devinit sta2x11_vip_init_one(struct pci_dev *pdev,
> const struct pci_device_id *ent)
> {
> @@ -1212,10 +805,17 @@ static int __devinit sta2x11_vip_init_one(struct pci_dev *pdev,
> struct sta2x11_vip *vip;
> struct vip_config *config;
>
> + /* Check if hardware support 26-bit DMA */
> + if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(26))) {
> + dev_err(&pdev->dev, "26-bit DMA addressing not available\n");
> + return -EINVAL;
> + }
> + /* Enable PCI */
> ret = pci_enable_device(pdev);
> if (ret)
> return ret;
>
> + /* Get VIP platform data */
> config = dev_get_platdata(&pdev->dev);
> if (!config) {
> dev_info(&pdev->dev, "VIP slot disabled\n");
> @@ -1223,6 +823,7 @@ static int __devinit sta2x11_vip_init_one(struct pci_dev *pdev,
> goto disable;
> }
>
> + /* Power configuration */
> ret = vip_gpio_reserve(&pdev->dev, config->pwr_pin, 0,
> config->pwr_name);
> if (ret)
> @@ -1237,7 +838,6 @@ static int __devinit sta2x11_vip_init_one(struct pci_dev *pdev,
> goto disable;
> }
> }
> -
> if (config->pwr_pin != -1) {
> /* Datasheet says 5ms between PWR and RST */
> usleep_range(5000, 25000);
> @@ -1251,17 +851,20 @@ static int __devinit sta2x11_vip_init_one(struct pci_dev *pdev,
> }
> usleep_range(5000, 25000);
>
> + /* Allocate a new VIP instance */
> vip = kzalloc(sizeof(struct sta2x11_vip), GFP_KERNEL);
> if (!vip) {
> ret = -ENOMEM;
> goto release_gpios;
> }
> -
> vip->pdev = pdev;
> vip->std = V4L2_STD_PAL;
> vip->format = formats_50[0];
> vip->config = config;
>
> + ret = sta2x11_vip_init_controls(vip);
> + if (ret)
> + goto free_mem;
> if (v4l2_device_register(&pdev->dev, &vip->v4l2_dev))
> goto free_mem;
>
> @@ -1271,46 +874,52 @@ static int __devinit sta2x11_vip_init_one(struct pci_dev *pdev,
>
> pci_set_master(pdev);
>
> - ret = pci_request_regions(pdev, DRV_NAME);
> + ret = pci_request_regions(pdev, KBUILD_MODNAME);
> if (ret)
> goto unreg;
>
> vip->iomem = pci_iomap(pdev, 0, 0x100);
> if (!vip->iomem) {
> - ret = -ENOMEM; /* FIXME */
> + ret = -ENOMEM;
> goto release;
> }
>
> pci_enable_msi(pdev);
>
> - INIT_LIST_HEAD(&vip->capture);
> + /* Initialize buffer */
> + ret = sta2x11_vip_init_buffer(vip);
> + if (ret)
> + goto unmap;
> +
> spin_lock_init(&vip->slock);
> - mutex_init(&vip->mutex);
> - vip->started = 0;
> - vip->disabled = 0;
>
> ret = request_irq(pdev->irq,
> (irq_handler_t) vip_irq,
> - IRQF_SHARED, DRV_NAME, vip);
> + IRQF_SHARED, KBUILD_MODNAME, vip);
> if (ret) {
> dev_err(&pdev->dev, "request_irq failed\n");
> ret = -ENODEV;
> - goto unmap;
> + goto release_buf;
> }
>
> + /* Alloc, initialize and register video device */
> vip->video_dev = video_device_alloc();
> if (!vip->video_dev) {
> ret = -ENOMEM;
> goto release_irq;
> }
>
> - *(vip->video_dev) = video_dev_template;
> + vip->video_dev = &video_dev_template;
> + vip->video_dev->v4l2_dev = &vip->v4l2_dev;
> + vip->video_dev->queue = &vip->vb_vidq;
> + vip->video_dev->flags |= V4L2_FL_USES_V4L2_FH | V4L2_FL_USE_FH_PRIO;
Been there, done that :-)
V4L2_FL_USE_FH_PRIO is a bit number, not a bit mask. Use set_bit instead:
set_bit(V4L2_FL_USE_FH_PRIO, &vip->video_dev->flags);
No need to set V4L2_FL_USES_V4L2_FH, BTW. That will be set automatically as soon
as v4l2_fh_open is called.
Regards,
Hans
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 3/3 v2] [media] sta2x11_vip: convert to videobuf2 and control framework
2012-08-06 8:42 ` Hans Verkuil
@ 2012-08-06 8:55 ` Federico Vaga
0 siblings, 0 replies; 22+ messages in thread
From: Federico Vaga @ 2012-08-06 8:55 UTC (permalink / raw)
To: Hans Verkuil
Cc: Mauro Carvalho Chehab, Pawel Osciak, Marek Szyprowski,
Hans Verkuil, Giancarlo Asnaghi, linux-media, linux-kernel,
Jonathan Corbet
> > + vip->video_dev->flags |= V4L2_FL_USES_V4L2_FH |
> > V4L2_FL_USE_FH_PRIO;
> Been there, done that :-)
>
> V4L2_FL_USE_FH_PRIO is a bit number, not a bit mask. Use set_bit
> instead:
>
> set_bit(V4L2_FL_USE_FH_PRIO, &vip->video_dev->flags);
>
> No need to set V4L2_FL_USES_V4L2_FH, BTW. That will be set
> automatically as soon as v4l2_fh_open is called.
I saw "unsigned long flags;" in the header but without reading the
comment :) Thank you. I will test it in these days but I think it's all
done.
--
Federico Vaga
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 1/3] [media] adv7180: remove {query/g_/s_}ctrl
2012-07-31 20:20 ` Federico Vaga
@ 2012-08-12 1:46 ` Mauro Carvalho Chehab
0 siblings, 0 replies; 22+ messages in thread
From: Mauro Carvalho Chehab @ 2012-08-12 1:46 UTC (permalink / raw)
To: Federico Vaga
Cc: Mauro Carvalho Chehab, Pawel Osciak, Marek Szyprowski,
Hans Verkuil, Giancarlo Asnaghi, linux-media, linux-kernel,
Jonathan Corbet
Em 31-07-2012 17:20, Federico Vaga escreveu:
> I'm sorry for the email duplication, I press the wrong key on git-send email.
> Ignore these emails. Sorry
>
Ok, I'll mark those patches as "RFC" per your request.
Regards,
mauro
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: Update VIP to videobuf2 and control framework
2012-08-01 13:04 ` Jonathan Corbet
@ 2012-08-16 11:29 ` Federico Vaga
0 siblings, 0 replies; 22+ messages in thread
From: Federico Vaga @ 2012-08-16 11:29 UTC (permalink / raw)
To: Jonathan Corbet
Cc: Hans Verkuil, Mauro Carvalho Chehab, Pawel Osciak,
Marek Szyprowski, Hans Verkuil, Giancarlo Asnaghi, linux-media,
linux-kernel
In data mercoledì 1 agosto 2012 07:04:18, Jonathan Corbet ha scritto:
> On Wed, 1 Aug 2012 08:41:56 +0200
>
> Hans Verkuil <hverkuil@xs4all.nl> wrote:
> > > The second patch adds a new memory allocator for the videobuf2. I
> > > name it videobuf2-dma-streaming but I think "streaming" is not
> > > the best choice, so suggestions are welcome. My inspiration for
> > > this buffer come from videobuf-dma-contig (cached) version. After
> > > I made this buffer I found the videobuf2-dma-nc made by Jonathan
> > > Corbet and I improve the allocator with some suggestions
> > > (http://patchwork.linuxtv.org/patch/7441/). The VIP doesn't work
> > > with videobu2-dma-contig and I think this solution is easier the
> > > sg.>
> > I leave this to the vb2 experts. It's not obvious to me why we would
> > need a fourth memory allocator.
>
> I first wrote my version after observing that performance dropped by a
> factor of three on the OLPC XO 1.75 when using contiguous, coherent
> memory. If the architecture needs to turn off caching, things really
> slow down, to the point that it's unusable. There's no real reason
> why a V4L2 device shouldn't be able to use streaming mappings in this
> situation; it performs better and doesn't eat into the limited
> amounts of coherent DMA space available on some systems.
>
> I never got my version into a mergeable state only because I finally
> figured out how to bludgeon the hardware into doing s/g DMA and didn't
> need it anymore. But I think it's a worthwhile functionality to
> have, and, with CMA, it could be the preferred mode for a number of
> devices.
>
> jon
I think that the memory allocator is the most questionable patch, but if
there are not any other comments I will send my three patches for the
inclusion. It is summer, time for vacation, so I'll wait for another
week or two for critical comments and then I will send patches.
--
Federico Vaga
^ permalink raw reply [flat|nested] 22+ messages in thread
* RE: [PATCH 2/3] [media] videobuf2-dma-streaming: new videobuf2 memory allocator
2012-07-31 20:17 ` [PATCH 2/3] [media] videobuf2-dma-streaming: new videobuf2 memory allocator Federico Vaga
@ 2012-08-20 8:03 ` Marek Szyprowski
2012-08-24 13:23 ` Federico Vaga
0 siblings, 1 reply; 22+ messages in thread
From: Marek Szyprowski @ 2012-08-20 8:03 UTC (permalink / raw)
To: 'Federico Vaga', 'Mauro Carvalho Chehab',
'Pawel Osciak', 'Hans Verkuil'
Cc: 'Giancarlo Asnaghi', linux-media, linux-kernel,
'Jonathan Corbet', Tomasz Stanislawski
Hello,
I'm really sorry for a late reply, but I was a bit busy with other stuff.
On Tuesday, July 31, 2012 10:17 PM Federico Vaga wrote:
> Signed-off-by: Federico Vaga <federico.vaga@gmail.com>
> ---
> drivers/media/video/Kconfig | 6 +-
> drivers/media/video/Makefile | 1 +
> drivers/media/video/videobuf2-dma-streaming.c | 187 ++++++++++++++++++++++++++
> include/media/videobuf2-dma-streaming.h | 24 ++++
> 4 file modificati, 217 inserzioni(+). 1 rimozione(-)
> create mode 100644 drivers/media/video/videobuf2-dma-streaming.c
> create mode 100644 include/media/videobuf2-dma-streaming.h
>
> diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
> index be6d718..6c60b59 100644
> --- a/drivers/media/video/Kconfig
> +++ b/drivers/media/video/Kconfig
> @@ -59,6 +59,10 @@ config VIDEOBUF2_DMA_NC
> select VIDEOBUF2_CORE
> select VIDEOBUF2_MEMOPS
> tristate
> +config VIDEOBUF2_DMA_STREAMING
> + select VIDEOBUF2_CORE
> + select VIDEOBUF2_MEMOPS
> + tristate
>
> config VIDEOBUF2_VMALLOC
> select VIDEOBUF2_CORE
> @@ -844,7 +848,7 @@ config STA2X11_VIP
> tristate "STA2X11 VIP Video For Linux"
> depends on STA2X11
> select VIDEO_ADV7180 if VIDEO_HELPER_CHIPS_AUTO
> - select VIDEOBUF_DMA_CONTIG
> + select VIDEOBUF2_DMA_STREAMING
This doesn't look like a part of this part.
> depends on PCI && VIDEO_V4L2 && VIRT_TO_BUS
> help
> Say Y for support for STA2X11 VIP (Video Input Port) capture
> diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
> index 30234af..c1a08b9e 100644
> --- a/drivers/media/video/Makefile
> +++ b/drivers/media/video/Makefile
> @@ -140,6 +140,7 @@ obj-$(CONFIG_VIDEOBUF2_VMALLOC) += videobuf2-vmalloc.o
> obj-$(CONFIG_VIDEOBUF2_DMA_CONTIG) += videobuf2-dma-contig.o
> obj-$(CONFIG_VIDEOBUF2_DMA_SG) += videobuf2-dma-sg.o
> obj-$(CONFIG_VIDEOBUF2_DMA_NC) += videobuf2-dma-nc.o
> +obj-$(CONFIG_VIDEOBUF2_DMA_STREAMING) += videobuf2-dma-streaming.o
>
> obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o
>
> diff --git a/drivers/media/video/videobuf2-dma-streaming.c b/drivers/media/video/videobuf2-
> dma-streaming.c
> new file mode 100644
> index 0000000..d96d3d9
> --- /dev/null
> +++ b/drivers/media/video/videobuf2-dma-streaming.c
> @@ -0,0 +1,187 @@
> +/*
> + * videobuf2-dma-streaming.c - DMA streaming memory allocator for videobuf2
> + *
> + * Copyright (C) 2012 Federico Vaga <federico.vaga@gmail.com>
> + * *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/pagemap.h>
> +#include <linux/dma-mapping.h>
> +
> +#include <media/videobuf2-core.h>
> +#include <media/videobuf2-dma-streaming.h>
> +#include <media/videobuf2-memops.h>
> +
> +struct vb2_streaming_conf {
> + struct device *dev;
> +};
> +struct vb2_streaming_buf {
> + struct vb2_streaming_conf *conf;
> + void *vaddr;
> +
> + dma_addr_t dma_handle;
> +
> + unsigned long size;
> + struct vm_area_struct *vma;
> +
> + atomic_t refcount;
> + struct vb2_vmarea_handler handler;
> +};
> +
> +static void vb2_dma_streaming_put(void *buf_priv)
> +{
> + struct vb2_streaming_buf *buf = buf_priv;
> +
> + if (atomic_dec_and_test(&buf->refcount)) {
> + dma_unmap_single(buf->conf->dev, buf->dma_handle, buf->size,
> + DMA_FROM_DEVICE);
> + free_pages_exact(buf->vaddr, buf->size);
> + kfree(buf);
> + }
> +
> +}
> +
> +static void *vb2_dma_streaming_alloc(void *alloc_ctx, unsigned long size)
> +{
> + struct vb2_streaming_conf *conf = alloc_ctx;
> + struct vb2_streaming_buf *buf;
> + int err;
> +
> + buf = kzalloc(sizeof *buf, GFP_KERNEL);
> + if (!buf)
> + return ERR_PTR(-ENOMEM);
> + buf->vaddr = alloc_pages_exact(size, GFP_KERNEL | GFP_DMA);
> + if (!buf->vaddr) {
> + err = -ENOMEM;
> + goto out;
> + }
> + buf->dma_handle = dma_map_single(conf->dev, buf->vaddr, size,
> + DMA_FROM_DEVICE);
> + err = dma_mapping_error(conf->dev, buf->dma_handle);
> + if (err) {
> + dev_err(conf->dev, "dma_map_single failed\n");
> +
> + free_pages_exact(buf->vaddr, size);
> + buf->vaddr = NULL;
> + goto out_pages;
> + }
> + buf->conf = conf;
> + buf->size = size;
> + buf->handler.refcount = &buf->refcount;
> + buf->handler.put = vb2_dma_streaming_put;
> + buf->handler.arg = buf;
> +
> + atomic_inc(&buf->refcount);
> + return buf;
> +
> +out_pages:
> + free_pages_exact(buf->vaddr, buf->size);
> +out:
> + kfree(buf);
> + return ERR_PTR(err);
> +}
> +
> +static void *vb2_dma_streaming_cookie(void *buf_priv)
> +{
> + struct vb2_streaming_buf *buf = buf_priv;
> +
> + return (void *)buf->dma_handle;
> +}
> +
> +static void *vb2_dma_streaming_vaddr(void *buf_priv)
> +{
> + struct vb2_streaming_buf *buf = buf_priv;
> +
> + if (!buf)
> + return NULL;
> + return buf->vaddr;
> +}
> +
> +static unsigned int vb2_dma_streaming_num_users(void *buf_priv)
> +{
> + struct vb2_streaming_buf *buf = buf_priv;
> +
> + return atomic_read(&buf->refcount);
> +}
> +
> +static int vb2_dma_streaming_mmap(void *buf_priv, struct vm_area_struct *vma)
> +{
> + struct vb2_streaming_buf *buf = buf_priv;
> + unsigned long pos, start = vma->vm_start;
> + unsigned long size;
> + struct page *page;
> + int err;
> +
> + /* Try to remap memory */
> + size = vma->vm_end - vma->vm_start;
> + size = (size < buf->size) ? size : buf->size;
> + pos = (unsigned long)buf->vaddr;
> +
> + while (size > 0) {
> + page = virt_to_page((void *)pos);
> + if (!page) {
> + dev_err(buf->conf->dev, "mmap: virt_to_page failed\n");
> + return -ENOMEM;
> + }
> + err = vm_insert_page(vma, start, page);
> + if (err) {
> + dev_err(buf->conf->dev, "mmap: insert failed %d\n", err);
> + return -ENOMEM;
> + }
> + start += PAGE_SIZE;
> + pos += PAGE_SIZE;
> +
> + if (size > PAGE_SIZE)
> + size -= PAGE_SIZE;
> + else
> + size = 0;
> + }
> +
> +
> + vma->vm_ops = &vb2_common_vm_ops;
> + vma->vm_flags |= VM_DONTEXPAND;
> + vma->vm_private_data = &buf->handler;
> +
> + vma->vm_ops->open(vma);
> +
> + return 0;
> +}
> +
> +const struct vb2_mem_ops vb2_dma_streaming_memops = {
> + .alloc = vb2_dma_streaming_alloc,
> + .put = vb2_dma_streaming_put,
> + .cookie = vb2_dma_streaming_cookie,
> + .vaddr = vb2_dma_streaming_vaddr,
> + .mmap = vb2_dma_streaming_mmap,
> + .num_users = vb2_dma_streaming_num_users,
> +};
> +EXPORT_SYMBOL_GPL(vb2_dma_streaming_memops);
> +
> +void *vb2_dma_streaming_init_ctx(struct device *dev)
> +{
> + struct vb2_streaming_conf *conf;
> +
> + conf = kmalloc(sizeof *conf, GFP_KERNEL);
> + if (!conf)
> + return ERR_PTR(-ENOMEM);
> +
> + conf->dev = dev;
> +
> + return conf;
> +}
> +EXPORT_SYMBOL_GPL(vb2_dma_streaming_init_ctx);
> +
> +void vb2_dma_streaming_cleanup_ctx(void *alloc_ctx)
> +{
> + kfree(alloc_ctx);
> +}
> +EXPORT_SYMBOL_GPL(vb2_dma_streaming_cleanup_ctx);
> +
> +MODULE_DESCRIPTION("DMA-streaming memory allocator for videobuf2");
> +MODULE_AUTHOR("Federico Vaga <federico.vaga@gmail.com>");
> +MODULE_LICENSE("GPL v2");
> diff --git a/include/media/videobuf2-dma-streaming.h b/include/media/videobuf2-dma-streaming.h
> new file mode 100644
> index 0000000..89cbd06
> --- /dev/null
> +++ b/include/media/videobuf2-dma-streaming.h
> @@ -0,0 +1,24 @@
> +/*
> + * videobuf2-dma-streaming.h - DMA steaming memory allocator for videobuf2
> + *
> + * Copyright (C) 2012 Federico Vaga
> + *
> + * Author: Federico Vaga <federico.vaga@gmail.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation.
> + */
> +
> +#ifndef _MEDIA_VIDEOBUF2_DMA_STREAMING_H
> +#define _MEDIA_VIDEOBUF2_DMA_STREAMING_H
> +
> +#include <media/videobuf2-core.h>
> +#include <linux/dma-mapping.h>
> +
> +void *vb2_dma_streaming_init_ctx(struct device *dev);
> +void vb2_dma_streaming_cleanup_ctx(void *alloc_ctx);
> +
> +extern const struct vb2_mem_ops vb2_dma_streaming_memops;
> +
> +#endif
> --
> 1.7.11.2
I'm aware of the fact that some system might require such method of memory allocation.
I don't want to delay merging it. I hope that one day it will be finally possible to
use dma_alloc_attrs() from dma-mapping subsystem for this purpose and extended
videobuf2-dma-contig will handle it.
Getting back to your patch - in your approach cpu cache handling is missing. I suspect
that it worked fine only because it has been tested on some simple platform without
any cpu caches (or with very small ones). Please check the following thread:
http://www.spinics.net/lists/linux-media/msg51768.html where Tomasz has posted his
ongoing effort on updating and extending videobuf2 and dma-contig allocator.
Especially the patch http://www.spinics.net/lists/linux-media/msg51776.html will be
interesting for you, because cpu cache synchronization (dma_sync_single_for_device /
dma_sync_single_for_cpu) should be called from prepare/finish callbacks.
Best regards
--
Marek Szyprowski
Samsung Poland R&D Center
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 2/3] [media] videobuf2-dma-streaming: new videobuf2 memory allocator
2012-08-20 8:03 ` Marek Szyprowski
@ 2012-08-24 13:23 ` Federico Vaga
2012-08-24 13:40 ` Marek Szyprowski
0 siblings, 1 reply; 22+ messages in thread
From: Federico Vaga @ 2012-08-24 13:23 UTC (permalink / raw)
To: Marek Szyprowski
Cc: 'Mauro Carvalho Chehab', 'Pawel Osciak',
'Hans Verkuil', 'Giancarlo Asnaghi', linux-media,
linux-kernel, 'Jonathan Corbet', Tomasz Stanislawski
> Getting back to your patch - in your approach cpu cache handling is
> missing. I suspect that it worked fine only because it has been
> tested on some simple platform without any cpu caches (or with very
> small ones).
Is missing from the memory allocator because I do it on the device
driver. The current operations don't allow me to do that in the memory
allocator.
> Please check the following thread:
> http://www.spinics.net/lists/linux-media/msg51768.html where Tomasz
> has posted his ongoing effort on updating and extending videobuf2 and
> dma-contig allocator. Especially the patch
> http://www.spinics.net/lists/linux-media/msg51776.html will be
> interesting for you, because cpu cache synchronization
> (dma_sync_single_for_device / dma_sync_single_for_cpu) should be
> called from prepare/finish callbacks.
You are right, it is interesting because avoid me to use cache sync in
my driver. Can I work on these patches?
>From this page I understand that these patches are not approved yet
https://patchwork.kernel.org/project/linux-media/list/?page=2
--
Federico Vaga
^ permalink raw reply [flat|nested] 22+ messages in thread
* RE: [PATCH 2/3] [media] videobuf2-dma-streaming: new videobuf2 memory allocator
2012-08-24 13:23 ` Federico Vaga
@ 2012-08-24 13:40 ` Marek Szyprowski
2012-08-24 13:48 ` Federico Vaga
0 siblings, 1 reply; 22+ messages in thread
From: Marek Szyprowski @ 2012-08-24 13:40 UTC (permalink / raw)
To: 'Federico Vaga'
Cc: 'Mauro Carvalho Chehab', 'Pawel Osciak',
'Hans Verkuil', 'Giancarlo Asnaghi', linux-media,
linux-kernel, 'Jonathan Corbet', Tomasz Stanislawski
Hello,
On Friday, August 24, 2012 3:23 PM Federico Vaga wrote:
> > Getting back to your patch - in your approach cpu cache handling is
> > missing. I suspect that it worked fine only because it has been
> > tested on some simple platform without any cpu caches (or with very
> > small ones).
>
> Is missing from the memory allocator because I do it on the device
> driver. The current operations don't allow me to do that in the memory
> allocator.
Memory allocator module is much more appropriate place for it. dma-sg
allocator also needs a huge cleanup in this area...
> > Please check the following thread:
> > http://www.spinics.net/lists/linux-media/msg51768.html where Tomasz
> > has posted his ongoing effort on updating and extending videobuf2 and
> > dma-contig allocator. Especially the patch
> > http://www.spinics.net/lists/linux-media/msg51776.html will be
> > interesting for you, because cpu cache synchronization
> > (dma_sync_single_for_device / dma_sync_single_for_cpu) should be
> > called from prepare/finish callbacks.
>
> You are right, it is interesting because avoid me to use cache sync in
> my driver. Can I work on these patches?
>
> From this page I understand that these patches are not approved yet
> https://patchwork.kernel.org/project/linux-media/list/?page=2
You can take the patch which adds prepare/finish methods to memory
allocators. It should not have any dependency on the other stuff from
that thread. I'm fine with merging it either together with Your patch
or via Tomasz's patchset, whatever comes first.
Best regards
--
Marek Szyprowski
Samsung Poland R&D Center
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 2/3] [media] videobuf2-dma-streaming: new videobuf2 memory allocator
2012-08-24 13:40 ` Marek Szyprowski
@ 2012-08-24 13:48 ` Federico Vaga
0 siblings, 0 replies; 22+ messages in thread
From: Federico Vaga @ 2012-08-24 13:48 UTC (permalink / raw)
To: Marek Szyprowski
Cc: 'Mauro Carvalho Chehab', 'Pawel Osciak',
'Hans Verkuil', 'Giancarlo Asnaghi', linux-media,
linux-kernel, 'Jonathan Corbet', Tomasz Stanislawski
> You can take the patch which adds prepare/finish methods to memory
> allocators. It should not have any dependency on the other stuff from
> that thread. I'm fine with merging it either together with Your patch
> or via Tomasz's patchset, whatever comes first.
Thank you. I'll do the job
--
Federico Vaga
^ permalink raw reply [flat|nested] 22+ messages in thread
end of thread, other threads:[~2012-08-24 13:44 UTC | newest]
Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-07-31 20:17 Update VIP to videobuf2 and control framework Federico Vaga
2012-07-31 20:17 ` [PATCH 1/3] [media] adv7180: remove {query/g_/s_}ctrl Federico Vaga
2012-07-31 20:20 ` Federico Vaga
2012-08-12 1:46 ` Mauro Carvalho Chehab
2012-07-31 20:17 ` [PATCH 2/3] [media] videobuf2-dma-streaming: new videobuf2 memory allocator Federico Vaga
2012-08-20 8:03 ` Marek Szyprowski
2012-08-24 13:23 ` Federico Vaga
2012-08-24 13:40 ` Marek Szyprowski
2012-08-24 13:48 ` Federico Vaga
2012-07-31 20:17 ` [PATCH 3/3] [media] sta2x11_vip: convert to videobuf2 and control framework Federico Vaga
2012-08-06 8:17 ` [PATCH 3/3 v2] " Federico Vaga
2012-08-06 8:42 ` Hans Verkuil
2012-08-06 8:55 ` Federico Vaga
2012-07-31 20:27 ` Update VIP " Federico Vaga
2012-08-01 6:41 ` Hans Verkuil
2012-08-01 13:04 ` Jonathan Corbet
2012-08-16 11:29 ` Federico Vaga
2012-08-05 17:11 ` Federico Vaga
2012-08-06 7:26 ` Hans Verkuil
2012-08-06 7:38 ` Federico Vaga
2012-08-06 7:36 ` Hans Verkuil
2012-08-06 8:20 ` Federico Vaga
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).