media: zoran: Add vb_queue
authorCorentin Labbe <clabbe@baylibre.com>
Fri, 25 Sep 2020 18:30:46 +0000 (20:30 +0200)
committerMauro Carvalho Chehab <mchehab+huawei@kernel.org>
Thu, 1 Oct 2020 07:59:38 +0000 (09:59 +0200)
This patchs adds a vb_queue without using it.
This reduce the final VB2 conversion patch.

Signed-off-by: Corentin Labbe <clabbe@baylibre.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
drivers/staging/media/zoran/Kconfig
drivers/staging/media/zoran/zoran.h
drivers/staging/media/zoran/zoran_card.c
drivers/staging/media/zoran/zoran_driver.c

index 34a1813..ddf38a9 100644 (file)
@@ -2,6 +2,7 @@ config VIDEO_ZORAN
        tristate "Zoran ZR36057/36067 Video For Linux (Deprecated)"
        depends on PCI && I2C_ALGOBIT && VIDEO_V4L2 && VIRT_TO_BUS
        depends on !ALPHA
+       select VIDEOBUF2_DMA_CONTIG
        help
          Say Y for support for MJPEG capture cards based on the Zoran
          36057/36067 PCI controller chipset. This includes the Iomega
index 727ba67..294e52d 100644 (file)
@@ -21,6 +21,9 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-fh.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-v4l2.h>
+#include <media/videobuf2-dma-contig.h>
 
 #define ZR_NORM_PAL 0
 #define ZR_NORM_NTSC 1
@@ -33,6 +36,18 @@ struct zoran_sync {
        u64 ts;                 /* timestamp */
 };
 
+struct zr_buffer {
+       /* common v4l buffer stuff -- must be first */
+       struct vb2_v4l2_buffer          vbuf;
+       struct list_head                queue;
+};
+
+static inline struct zr_buffer *vb2_to_zr_buffer(struct vb2_buffer *vb)
+{
+       struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+       return container_of(vbuf, struct zr_buffer, vbuf);
+}
 
 #define ZORAN_NAME    "ZORAN"  /* name of the device */
 
@@ -104,6 +119,7 @@ enum zoran_buffer_state {
 };
 
 enum zoran_map_mode {
+       ZORAN_MAP_MODE_NONE,
        ZORAN_MAP_MODE_RAW,
        ZORAN_MAP_MODE_JPG_REC,
 #define ZORAN_MAP_MODE_JPG ZORAN_MAP_MODE_JPG_REC
@@ -250,6 +266,7 @@ struct zoran {
        struct v4l2_device v4l2_dev;
        struct v4l2_ctrl_handler hdl;
        struct video_device *video_dev;
+       struct vb2_queue vq;
 
        struct i2c_adapter i2c_adapter; /* */
        struct i2c_algo_bit_data i2c_algo;      /* */
@@ -320,6 +337,7 @@ struct zoran {
        unsigned long jpg_err_seq;      /* last seq_num before error */
        unsigned long jpg_err_shift;
        unsigned long jpg_queued_num;   /* count of frames queued since grab/play started */
+       unsigned long vbseq;
 
        /* zr36057's code buffer table */
        __le32 *stat_com;               /* stat_com[i] is indexed by dma_head/tail & BUZ_MASK_STAT_COM */
@@ -350,15 +368,23 @@ struct zoran {
        int num_errors;
        int JPEG_max_missed;
        int JPEG_min_missed;
+       unsigned int prepared;
+       unsigned int queued;
 
        u32 last_isr;
        unsigned long frame_num;
+       int running;
+       int buf_in_reserve;
 
        wait_queue_head_t test_q;
 
        dma_addr_t p_sc;
        __le32 *stat_comb;
        dma_addr_t p_scb;
+       enum zoran_map_mode map_mode;
+       struct list_head queued_bufs;
+       spinlock_t queued_bufs_lock; /* Protects queued_bufs */
+       struct zr_buffer *inuse[BUZ_NUM_STAT_COM * 2];
 };
 
 static inline struct zoran *to_zoran(struct v4l2_device *v4l2_dev)
@@ -376,3 +402,7 @@ static inline struct zoran *to_zoran(struct v4l2_device *v4l2_dev)
 #define btaor(dat, mask, adr) btwrite((dat) | ((mask) & btread(adr)), adr)
 
 #endif
+
+int zoran_queue_init(struct zoran *zr, struct vb2_queue *vq);
+void zoran_queue_exit(struct zoran *zr);
+int zr_set_buf(struct zoran *zr);
index 49a1d9e..fed368b 100644 (file)
@@ -970,6 +970,9 @@ static int zr36057_init(struct zoran *zr)
         * another day.
         */
        zr->video_dev->vfl_dir = VFL_DIR_M2M;
+
+       zoran_queue_init(zr, &zr->vq);
+
        err = video_register_device(zr->video_dev, VFL_TYPE_VIDEO, video_nr[zr->id]);
        if (err < 0)
                goto exit_statcomb;
@@ -1005,6 +1008,8 @@ static void zoran_remove(struct pci_dev *pdev)
        if (!zr->initialized)
                goto exit_free;
 
+       zoran_queue_exit(zr);
+
        /* unregister videocodec bus */
        if (zr->codec)
                videocodec_detach(zr->codec);
@@ -1283,6 +1288,8 @@ static int zoran_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (zr36057_init(zr) < 0)
                goto zr_detach_vfe;
 
+       zr->map_mode = ZORAN_MAP_MODE_RAW;
+
        return 0;
 
 zr_detach_vfe:
index 5ac832e..e962fc6 100644 (file)
@@ -2272,3 +2272,236 @@ const struct video_device zoran_template = {
        .tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM,
 };
 
+static int zr_vb2_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes,
+                             unsigned int sizes[], struct device *alloc_devs[])
+{
+       struct zoran *zr = vb2_get_drv_priv(vq);
+       unsigned int size = zr->buffer_size;
+
+       pci_dbg(zr->pci_dev, "%s nbuf=%u nplanes=%u", __func__, *nbuffers, *nplanes);
+
+       zr->buf_in_reserve = 0;
+
+       if (*nbuffers < vq->min_buffers_needed)
+               *nbuffers = vq->min_buffers_needed;
+
+       if (*nplanes)
+               if (sizes[0] < size)
+                       return -EINVAL;
+               else
+                       return 0;
+       *nplanes = 1;
+       sizes[0] = size;
+
+       return 0;
+}
+
+static void zr_vb2_queue(struct vb2_buffer *vb)
+{
+       struct zoran *zr = vb2_get_drv_priv(vb->vb2_queue);
+       struct zr_buffer *buf = vb2_to_zr_buffer(vb);
+       unsigned long flags;
+
+       spin_lock_irqsave(&zr->queued_bufs_lock, flags);
+       list_add_tail(&buf->queue, &zr->queued_bufs);
+       zr->buf_in_reserve++;
+       spin_unlock_irqrestore(&zr->queued_bufs_lock, flags);
+       if (zr->running == ZORAN_MAP_MODE_JPG_REC)
+               zoran_feed_stat_com(zr);
+       zr->queued++;
+}
+
+static int zr_vb2_prepare(struct vb2_buffer *vb)
+{
+       struct zoran *zr = vb2_get_drv_priv(vb->vb2_queue);
+
+       zr->prepared++;
+       return 0;
+}
+
+int zr_set_buf(struct zoran *zr)
+{
+       struct zr_buffer *buf;
+       struct vb2_v4l2_buffer *vbuf;
+       dma_addr_t phys_addr;
+       unsigned long flags;
+       u32 reg;
+
+       if (zr->running == ZORAN_MAP_MODE_NONE)
+               return 0;
+
+       if (zr->inuse[0]) {
+               buf = zr->inuse[0];
+               buf->vbuf.vb2_buf.timestamp = ktime_get_ns();
+               buf->vbuf.sequence = zr->vbseq++;
+               vbuf = &buf->vbuf;
+
+               buf->vbuf.field = V4L2_FIELD_INTERLACED;
+               vb2_set_plane_payload(&buf->vbuf.vb2_buf, 0, zr->buffer_size);
+               vb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_DONE);
+               zr->inuse[0] = NULL;
+       }
+
+       spin_lock_irqsave(&zr->queued_bufs_lock, flags);
+       if (list_empty(&zr->queued_bufs)) {
+               btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR);
+               vb2_queue_error(zr->video_dev->queue);
+               spin_unlock_irqrestore(&zr->queued_bufs_lock, flags);
+               return -EINVAL;
+       }
+       buf = list_first_entry_or_null(&zr->queued_bufs, struct zr_buffer, queue);
+       if (!buf) {
+               btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR);
+               vb2_queue_error(zr->video_dev->queue);
+               spin_unlock_irqrestore(&zr->queued_bufs_lock, flags);
+               return -EINVAL;
+       }
+       list_del(&buf->queue);
+       spin_unlock_irqrestore(&zr->queued_bufs_lock, flags);
+
+       vbuf = &buf->vbuf;
+       vbuf->vb2_buf.state = VB2_BUF_STATE_ACTIVE;
+       phys_addr = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0);
+
+       if (!phys_addr)
+               return -EINVAL;
+
+       zr->inuse[0] = buf;
+
+       reg = phys_addr;
+       btwrite(reg, ZR36057_VDTR);
+       if (zr->v4l_settings.height > BUZ_MAX_HEIGHT / 2)
+               reg += zr->v4l_settings.bytesperline;
+       btwrite(reg, ZR36057_VDBR);
+
+       reg = 0;
+       if (zr->v4l_settings.height > BUZ_MAX_HEIGHT / 2)
+               reg += zr->v4l_settings.bytesperline;
+       reg = (reg << ZR36057_VSSFGR_DispStride);
+       reg |= ZR36057_VSSFGR_VidOvf;
+       reg |= ZR36057_VSSFGR_SnapShot;
+       reg |= ZR36057_VSSFGR_FrameGrab;
+       btwrite(reg, ZR36057_VSSFGR);
+
+       btor(ZR36057_VDCR_VidEn, ZR36057_VDCR);
+       return 0;
+}
+
+static int zr_vb2_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+       struct zoran *zr = vq->drv_priv;
+       int j;
+
+       for (j = 0; j < BUZ_NUM_STAT_COM; j++) {
+               zr->stat_com[j] = cpu_to_le32(1);
+               zr->inuse[j] = NULL;
+       }
+
+       if (zr->map_mode != ZORAN_MAP_MODE_RAW) {
+               pci_info(zr->pci_dev, "START JPG\n");
+               zr36057_restart(zr);
+               zoran_init_hardware(zr);
+               if (zr->map_mode == ZORAN_MAP_MODE_JPG_REC)
+                       zr36057_enable_jpg(zr, BUZ_MODE_MOTION_DECOMPRESS);
+               else
+                       zr36057_enable_jpg(zr, BUZ_MODE_MOTION_COMPRESS);
+               zoran_feed_stat_com(zr);
+               jpeg_start(zr);
+               zr->running = zr->map_mode;
+               btor(ZR36057_ICR_IntPinEn, ZR36057_ICR);
+               return 0;
+       }
+
+       pci_info(zr->pci_dev, "START RAW\n");
+       zr36057_restart(zr);
+       zoran_init_hardware(zr);
+
+       zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
+       zr36057_set_memgrab(zr, 1);
+       zr->running = zr->map_mode;
+       btor(ZR36057_ICR_IntPinEn, ZR36057_ICR);
+       return 0;
+}
+
+static void zr_vb2_stop_streaming(struct vb2_queue *vq)
+{
+       struct zoran *zr = vq->drv_priv;
+       struct zr_buffer *buf;
+       unsigned long flags;
+       int j;
+
+       btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR);
+       if (zr->map_mode != ZORAN_MAP_MODE_RAW)
+               zr36057_enable_jpg(zr, BUZ_MODE_IDLE);
+       zr36057_set_memgrab(zr, 0);
+       zr->running = ZORAN_MAP_MODE_NONE;
+
+       zoran_set_pci_master(zr, 0);
+
+       if (!pass_through) {    /* Switch to color bar */
+               decoder_call(zr, video, s_stream, 0);
+               encoder_call(zr, video, s_routing, 2, 0, 0);
+       }
+
+       for (j = 0; j < BUZ_NUM_STAT_COM; j++) {
+               zr->stat_com[j] = cpu_to_le32(1);
+               if (!zr->inuse[j])
+                       continue;
+               buf = zr->inuse[j];
+               pci_dbg(zr->pci_dev, "%s clean buf %d\n", __func__, j);
+               vb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_ERROR);
+               zr->inuse[j] = NULL;
+       }
+
+       spin_lock_irqsave(&zr->queued_bufs_lock, flags);
+       while (!list_empty(&zr->queued_bufs)) {
+               buf = list_entry(zr->queued_bufs.next, struct zr_buffer, queue);
+               list_del(&buf->queue);
+               vb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_ERROR);
+               zr->buf_in_reserve--;
+       }
+       spin_unlock_irqrestore(&zr->queued_bufs_lock, flags);
+       if (zr->buf_in_reserve)
+               pci_err(zr->pci_dev, "Buffer remaining %d\n", zr->buf_in_reserve);
+       zr->map_mode = ZORAN_MAP_MODE_RAW;
+}
+
+static const struct vb2_ops zr_video_qops = {
+       .queue_setup            = zr_vb2_queue_setup,
+       .buf_queue              = zr_vb2_queue,
+       .buf_prepare            = zr_vb2_prepare,
+       .start_streaming        = zr_vb2_start_streaming,
+       .stop_streaming         = zr_vb2_stop_streaming,
+       .wait_prepare           = vb2_ops_wait_prepare,
+       .wait_finish            = vb2_ops_wait_finish,
+};
+
+int zoran_queue_init(struct zoran *zr, struct vb2_queue *vq)
+{
+       int err;
+
+       spin_lock_init(&zr->queued_bufs_lock);
+       INIT_LIST_HEAD(&zr->queued_bufs);
+
+       vq->dev = &zr->pci_dev->dev;
+       vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       vq->io_modes = VB2_USERPTR | VB2_DMABUF | VB2_MMAP | VB2_READ | VB2_WRITE;
+       vq->drv_priv = zr;
+       vq->buf_struct_size = sizeof(struct zr_buffer);
+       vq->ops = &zr_video_qops;
+       vq->mem_ops = &vb2_dma_contig_memops;
+       vq->gfp_flags = GFP_DMA32,
+       vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+       vq->min_buffers_needed = 9;
+       vq->lock = &zr->lock;
+       err = vb2_queue_init(vq);
+       if (err)
+               return err;
+       zr->video_dev->queue = vq;
+       return 0;
+}
+
+void zoran_queue_exit(struct zoran *zr)
+{
+       vb2_queue_release(zr->video_dev->queue);
+}