media: zoran: Add vb_queue

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>
This commit is contained in:
Corentin Labbe 2020-09-25 20:30:46 +02:00 committed by Mauro Carvalho Chehab
parent 1c3629cba0
commit b564cb6e0b
4 changed files with 271 additions and 0 deletions

View 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

View 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);

View 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:

View 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);
}