2019-05-27 08:55:06 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2017-04-07 14:55:19 -03:00
/*
* vimc - capture . c Virtual Media Controller Driver
*
* Copyright ( C ) 2015 - 2017 Helen Koike < helen . fornazier @ gmail . com >
*/
# include <media/v4l2-ioctl.h>
# include <media/videobuf2-core.h>
2021-07-30 15:18:29 +02:00
# include <media/videobuf2-dma-contig.h>
2017-04-07 14:55:19 -03:00
# include <media/videobuf2-vmalloc.h>
2017-06-19 14:00:18 -03:00
# include "vimc-common.h"
2019-01-21 20:05:01 -05:00
# include "vimc-streamer.h"
2017-06-19 14:00:18 -03:00
2022-06-16 11:07:45 +01:00
struct vimc_capture_device {
2017-04-07 14:55:19 -03:00
struct vimc_ent_device ved ;
struct video_device vdev ;
struct v4l2_pix_format format ;
struct vb2_queue queue ;
struct list_head buf_list ;
/*
* NOTE : in a real driver , a spin lock must be used to access the
* queue because the frames are generated from a hardware interruption
* and the isr is not allowed to sleep .
* Even if it is not necessary a spinlock in the vimc driver , we
* use it here as a code reference
*/
spinlock_t qlock ;
struct mutex lock ;
u32 sequence ;
2019-01-21 20:05:01 -05:00
struct vimc_stream stream ;
2019-10-03 09:59:42 -03:00
struct media_pad pad ;
2017-04-07 14:55:19 -03:00
} ;
2017-06-19 14:00:17 -03:00
static const struct v4l2_pix_format fmt_default = {
. width = 640 ,
. height = 480 ,
. pixelformat = V4L2_PIX_FMT_RGB24 ,
. field = V4L2_FIELD_NONE ,
2020-04-17 17:09:29 +02:00
. colorspace = V4L2_COLORSPACE_SRGB ,
2017-06-19 14:00:17 -03:00
} ;
2022-06-16 11:07:45 +01:00
struct vimc_capture_buffer {
2017-04-07 14:55:19 -03:00
/*
* struct vb2_v4l2_buffer must be the first element
* the videobuf2 framework will allocate this struct based on
* buf_struct_size and use the first sizeof ( struct vb2_buffer ) bytes of
* memory as a vb2_buffer
*/
struct vb2_v4l2_buffer vb2 ;
struct list_head list ;
} ;
2022-06-16 11:07:45 +01:00
static int vimc_capture_querycap ( struct file * file , void * priv ,
2017-04-07 14:55:19 -03:00
struct v4l2_capability * cap )
{
2019-01-14 10:27:45 -02:00
strscpy ( cap - > driver , VIMC_PDEV_NAME , sizeof ( cap - > driver ) ) ;
2018-09-10 08:19:14 -04:00
strscpy ( cap - > card , KBUILD_MODNAME , sizeof ( cap - > card ) ) ;
2017-04-07 14:55:19 -03:00
snprintf ( cap - > bus_info , sizeof ( cap - > bus_info ) ,
2019-01-30 08:43:51 -05:00
" platform:%s " , VIMC_PDEV_NAME ) ;
2017-04-07 14:55:19 -03:00
return 0 ;
}
2022-06-16 11:07:45 +01:00
static void vimc_capture_get_format ( struct vimc_ent_device * ved ,
2017-06-19 14:00:14 -03:00
struct v4l2_pix_format * fmt )
{
2022-06-16 11:07:45 +01:00
struct vimc_capture_device * vcapture = container_of ( ved , struct vimc_capture_device ,
2017-06-19 14:00:14 -03:00
ved ) ;
2022-06-16 11:07:45 +01:00
* fmt = vcapture - > format ;
2017-06-19 14:00:14 -03:00
}
2022-06-16 11:07:45 +01:00
static int vimc_capture_g_fmt_vid_cap ( struct file * file , void * priv ,
2017-04-07 14:55:19 -03:00
struct v4l2_format * f )
{
2022-06-16 11:07:45 +01:00
struct vimc_capture_device * vcapture = video_drvdata ( file ) ;
2017-04-07 14:55:19 -03:00
2022-06-16 11:07:45 +01:00
f - > fmt . pix = vcapture - > format ;
2017-04-07 14:55:19 -03:00
return 0 ;
}
2022-06-16 11:07:45 +01:00
static int vimc_capture_try_fmt_vid_cap ( struct file * file , void * priv ,
2017-06-19 14:00:17 -03:00
struct v4l2_format * f )
{
struct v4l2_pix_format * format = & f - > fmt . pix ;
2019-08-08 21:27:41 -03:00
const struct vimc_pix_map * vpix ;
2017-06-19 14:00:17 -03:00
format - > width = clamp_t ( u32 , format - > width , VIMC_FRAME_MIN_WIDTH ,
VIMC_FRAME_MAX_WIDTH ) & ~ 1 ;
format - > height = clamp_t ( u32 , format - > height , VIMC_FRAME_MIN_HEIGHT ,
VIMC_FRAME_MAX_HEIGHT ) & ~ 1 ;
2019-08-08 21:27:41 -03:00
/* Don't accept a pixelformat that is not on the table */
vpix = vimc_pix_map_by_pixelformat ( format - > pixelformat ) ;
if ( ! vpix ) {
format - > pixelformat = fmt_default . pixelformat ;
vpix = vimc_pix_map_by_pixelformat ( format - > pixelformat ) ;
}
/* TODO: Add support for custom bytesperline values */
format - > bytesperline = format - > width * vpix - > bpp ;
format - > sizeimage = format - > bytesperline * format - > height ;
2017-06-19 14:00:17 -03:00
if ( format - > field = = V4L2_FIELD_ANY )
format - > field = fmt_default . field ;
2019-08-08 21:27:41 -03:00
vimc_colorimetry_clamp ( format ) ;
2019-03-13 14:29:37 -04:00
2020-04-17 17:09:29 +02:00
if ( format - > colorspace = = V4L2_COLORSPACE_DEFAULT )
format - > colorspace = fmt_default . colorspace ;
2019-08-08 21:27:41 -03:00
return 0 ;
2017-06-19 14:00:17 -03:00
}
2022-06-16 11:07:45 +01:00
static int vimc_capture_s_fmt_vid_cap ( struct file * file , void * priv ,
2017-06-19 14:00:17 -03:00
struct v4l2_format * f )
{
2022-06-16 11:07:45 +01:00
struct vimc_capture_device * vcapture = video_drvdata ( file ) ;
2019-06-17 12:28:02 -04:00
int ret ;
2017-06-19 14:00:17 -03:00
/* Do not change the format while stream is on */
2022-06-16 11:07:45 +01:00
if ( vb2_is_busy ( & vcapture - > queue ) )
2017-06-19 14:00:17 -03:00
return - EBUSY ;
2022-06-16 11:07:45 +01:00
ret = vimc_capture_try_fmt_vid_cap ( file , priv , f ) ;
2019-06-17 12:28:02 -04:00
if ( ret )
return ret ;
2017-06-19 14:00:17 -03:00
2022-06-16 11:07:45 +01:00
dev_dbg ( vcapture - > ved . dev , " %s: format update: "
2017-06-19 14:00:17 -03:00
" old:%dx%d (0x%x, %d, %d, %d, %d) "
2022-06-16 11:07:45 +01:00
" new:%dx%d (0x%x, %d, %d, %d, %d) \n " , vcapture - > vdev . name ,
2017-06-19 14:00:17 -03:00
/* old */
2022-06-16 11:07:45 +01:00
vcapture - > format . width , vcapture - > format . height ,
vcapture - > format . pixelformat , vcapture - > format . colorspace ,
vcapture - > format . quantization , vcapture - > format . xfer_func ,
vcapture - > format . ycbcr_enc ,
2017-06-19 14:00:17 -03:00
/* new */
f - > fmt . pix . width , f - > fmt . pix . height ,
f - > fmt . pix . pixelformat , f - > fmt . pix . colorspace ,
f - > fmt . pix . quantization , f - > fmt . pix . xfer_func ,
f - > fmt . pix . ycbcr_enc ) ;
2022-06-16 11:07:45 +01:00
vcapture - > format = f - > fmt . pix ;
2017-06-19 14:00:17 -03:00
return 0 ;
}
2022-06-16 11:07:45 +01:00
static int vimc_capture_enum_fmt_vid_cap ( struct file * file , void * priv ,
2017-04-07 14:55:19 -03:00
struct v4l2_fmtdesc * f )
{
2020-04-21 15:57:43 +02:00
const struct vimc_pix_map * vpix ;
if ( f - > mbus_code ) {
if ( f - > index > 0 )
return - EINVAL ;
vpix = vimc_pix_map_by_code ( f - > mbus_code ) ;
} else {
vpix = vimc_pix_map_by_index ( f - > index ) ;
}
2019-08-08 21:27:41 -03:00
if ( ! vpix )
2017-04-07 14:55:19 -03:00
return - EINVAL ;
2019-08-08 21:27:41 -03:00
f - > pixelformat = vpix - > pixelformat ;
2017-06-19 14:00:17 -03:00
return 0 ;
}
2022-06-16 11:07:45 +01:00
static int vimc_capture_enum_framesizes ( struct file * file , void * fh ,
2017-06-19 14:00:17 -03:00
struct v4l2_frmsizeenum * fsize )
{
2019-08-08 21:27:41 -03:00
const struct vimc_pix_map * vpix ;
2017-06-19 14:00:17 -03:00
if ( fsize - > index )
return - EINVAL ;
2019-08-08 21:27:41 -03:00
/* Only accept code in the pix map table */
vpix = vimc_pix_map_by_code ( fsize - > pixel_format ) ;
if ( ! vpix )
2017-06-19 14:00:17 -03:00
return - EINVAL ;
fsize - > type = V4L2_FRMSIZE_TYPE_CONTINUOUS ;
fsize - > stepwise . min_width = VIMC_FRAME_MIN_WIDTH ;
fsize - > stepwise . max_width = VIMC_FRAME_MAX_WIDTH ;
fsize - > stepwise . min_height = VIMC_FRAME_MIN_HEIGHT ;
fsize - > stepwise . max_height = VIMC_FRAME_MAX_HEIGHT ;
2019-03-06 17:42:39 -05:00
fsize - > stepwise . step_width = 1 ;
fsize - > stepwise . step_height = 1 ;
2017-04-07 14:55:19 -03:00
return 0 ;
}
2022-06-16 11:07:45 +01:00
static const struct v4l2_file_operations vimc_capture_fops = {
2017-04-07 14:55:19 -03:00
. owner = THIS_MODULE ,
. open = v4l2_fh_open ,
. release = vb2_fop_release ,
. read = vb2_fop_read ,
. poll = vb2_fop_poll ,
. unlocked_ioctl = video_ioctl2 ,
. mmap = vb2_fop_mmap ,
} ;
2022-06-16 11:07:45 +01:00
static const struct v4l2_ioctl_ops vimc_capture_ioctl_ops = {
. vidioc_querycap = vimc_capture_querycap ,
2017-04-07 14:55:19 -03:00
2022-06-16 11:07:45 +01:00
. vidioc_g_fmt_vid_cap = vimc_capture_g_fmt_vid_cap ,
. vidioc_s_fmt_vid_cap = vimc_capture_s_fmt_vid_cap ,
. vidioc_try_fmt_vid_cap = vimc_capture_try_fmt_vid_cap ,
. vidioc_enum_fmt_vid_cap = vimc_capture_enum_fmt_vid_cap ,
. vidioc_enum_framesizes = vimc_capture_enum_framesizes ,
2017-04-07 14:55:19 -03:00
. vidioc_reqbufs = vb2_ioctl_reqbufs ,
. vidioc_create_bufs = vb2_ioctl_create_bufs ,
. vidioc_prepare_buf = vb2_ioctl_prepare_buf ,
. vidioc_querybuf = vb2_ioctl_querybuf ,
. vidioc_qbuf = vb2_ioctl_qbuf ,
. vidioc_dqbuf = vb2_ioctl_dqbuf ,
. vidioc_expbuf = vb2_ioctl_expbuf ,
. vidioc_streamon = vb2_ioctl_streamon ,
. vidioc_streamoff = vb2_ioctl_streamoff ,
} ;
2022-06-16 11:07:45 +01:00
static void vimc_capture_return_all_buffers ( struct vimc_capture_device * vcapture ,
2017-04-07 14:55:19 -03:00
enum vb2_buffer_state state )
{
2022-06-16 11:07:45 +01:00
struct vimc_capture_buffer * vbuf , * node ;
2017-04-07 14:55:19 -03:00
2022-06-16 11:07:45 +01:00
spin_lock ( & vcapture - > qlock ) ;
2017-04-07 14:55:19 -03:00
2022-06-16 11:07:45 +01:00
list_for_each_entry_safe ( vbuf , node , & vcapture - > buf_list , list ) {
2017-04-07 14:55:19 -03:00
list_del ( & vbuf - > list ) ;
vb2_buffer_done ( & vbuf - > vb2 . vb2_buf , state ) ;
}
2022-06-16 11:07:45 +01:00
spin_unlock ( & vcapture - > qlock ) ;
2017-04-07 14:55:19 -03:00
}
2022-06-16 11:07:45 +01:00
static int vimc_capture_start_streaming ( struct vb2_queue * vq , unsigned int count )
2017-04-07 14:55:19 -03:00
{
2022-06-16 11:07:45 +01:00
struct vimc_capture_device * vcapture = vb2_get_drv_priv ( vq ) ;
2017-04-07 14:55:19 -03:00
int ret ;
2022-06-16 11:07:45 +01:00
vcapture - > sequence = 0 ;
2017-04-07 14:55:19 -03:00
/* Start the media pipeline */
2022-08-31 16:13:33 +02:00
ret = video_device_pipeline_start ( & vcapture - > vdev , & vcapture - > stream . pipe ) ;
2017-04-07 14:55:19 -03:00
if ( ret ) {
2022-06-16 11:07:45 +01:00
vimc_capture_return_all_buffers ( vcapture , VB2_BUF_STATE_QUEUED ) ;
2017-04-07 14:55:19 -03:00
return ret ;
}
2022-06-16 11:07:45 +01:00
ret = vimc_streamer_s_stream ( & vcapture - > stream , & vcapture - > ved , 1 ) ;
2017-04-07 14:55:19 -03:00
if ( ret ) {
2022-08-31 16:13:33 +02:00
video_device_pipeline_stop ( & vcapture - > vdev ) ;
2022-06-16 11:07:45 +01:00
vimc_capture_return_all_buffers ( vcapture , VB2_BUF_STATE_QUEUED ) ;
2017-04-07 14:55:19 -03:00
return ret ;
}
return 0 ;
}
/*
* Stop the stream engine . Any remaining buffers in the stream queue are
* dequeued and passed on to the vb2 framework marked as STATE_ERROR .
*/
2022-06-16 11:07:45 +01:00
static void vimc_capture_stop_streaming ( struct vb2_queue * vq )
2017-04-07 14:55:19 -03:00
{
2022-06-16 11:07:45 +01:00
struct vimc_capture_device * vcapture = vb2_get_drv_priv ( vq ) ;
2017-04-07 14:55:19 -03:00
2022-06-16 11:07:45 +01:00
vimc_streamer_s_stream ( & vcapture - > stream , & vcapture - > ved , 0 ) ;
2017-04-07 14:55:19 -03:00
/* Stop the media pipeline */
2022-08-31 16:13:33 +02:00
video_device_pipeline_stop ( & vcapture - > vdev ) ;
2017-04-07 14:55:19 -03:00
/* Release all active buffers */
2022-06-16 11:07:45 +01:00
vimc_capture_return_all_buffers ( vcapture , VB2_BUF_STATE_ERROR ) ;
2017-04-07 14:55:19 -03:00
}
2022-06-16 11:07:45 +01:00
static void vimc_capture_buf_queue ( struct vb2_buffer * vb2_buf )
2017-04-07 14:55:19 -03:00
{
2022-06-16 11:07:45 +01:00
struct vimc_capture_device * vcapture = vb2_get_drv_priv ( vb2_buf - > vb2_queue ) ;
struct vimc_capture_buffer * buf = container_of ( vb2_buf ,
struct vimc_capture_buffer ,
2017-04-07 14:55:19 -03:00
vb2 . vb2_buf ) ;
2022-06-16 11:07:45 +01:00
spin_lock ( & vcapture - > qlock ) ;
list_add_tail ( & buf - > list , & vcapture - > buf_list ) ;
spin_unlock ( & vcapture - > qlock ) ;
2017-04-07 14:55:19 -03:00
}
2022-06-16 11:07:45 +01:00
static int vimc_capture_queue_setup ( struct vb2_queue * vq , unsigned int * nbuffers ,
2017-04-07 14:55:19 -03:00
unsigned int * nplanes , unsigned int sizes [ ] ,
struct device * alloc_devs [ ] )
{
2022-06-16 11:07:45 +01:00
struct vimc_capture_device * vcapture = vb2_get_drv_priv ( vq ) ;
2017-04-07 14:55:19 -03:00
if ( * nplanes )
2022-06-16 11:07:45 +01:00
return sizes [ 0 ] < vcapture - > format . sizeimage ? - EINVAL : 0 ;
2017-04-07 14:55:19 -03:00
/* We don't support multiplanes for now */
* nplanes = 1 ;
2022-06-16 11:07:45 +01:00
sizes [ 0 ] = vcapture - > format . sizeimage ;
2017-04-07 14:55:19 -03:00
return 0 ;
}
2022-06-16 11:07:45 +01:00
static int vimc_capture_buffer_prepare ( struct vb2_buffer * vb )
2017-04-07 14:55:19 -03:00
{
2022-06-16 11:07:45 +01:00
struct vimc_capture_device * vcapture = vb2_get_drv_priv ( vb - > vb2_queue ) ;
unsigned long size = vcapture - > format . sizeimage ;
2017-04-07 14:55:19 -03:00
if ( vb2_plane_size ( vb , 0 ) < size ) {
2022-06-16 11:07:45 +01:00
dev_err ( vcapture - > ved . dev , " %s: buffer too small (%lu < %lu) \n " ,
vcapture - > vdev . name , vb2_plane_size ( vb , 0 ) , size ) ;
2017-04-07 14:55:19 -03:00
return - EINVAL ;
}
return 0 ;
}
2022-06-16 11:07:45 +01:00
static const struct vb2_ops vimc_capture_qops = {
. start_streaming = vimc_capture_start_streaming ,
. stop_streaming = vimc_capture_stop_streaming ,
. buf_queue = vimc_capture_buf_queue ,
. queue_setup = vimc_capture_queue_setup ,
. buf_prepare = vimc_capture_buffer_prepare ,
2017-04-07 14:55:19 -03:00
/*
* Since q - > lock is set we can use the standard
* vb2_ops_wait_prepare / finish helper functions .
*/
. wait_prepare = vb2_ops_wait_prepare ,
. wait_finish = vb2_ops_wait_finish ,
} ;
2022-06-16 11:07:45 +01:00
static const struct media_entity_operations vimc_capture_mops = {
2019-10-30 09:30:40 -03:00
. link_validate = vimc_vdev_link_validate ,
2017-04-07 14:55:19 -03:00
} ;
2022-06-16 11:07:45 +01:00
static void vimc_capture_release ( struct vimc_ent_device * ved )
2019-02-21 08:47:28 -05:00
{
2022-06-16 11:07:45 +01:00
struct vimc_capture_device * vcapture =
container_of ( ved , struct vimc_capture_device , ved ) ;
2019-02-21 08:47:28 -05:00
2022-06-16 11:07:45 +01:00
media_entity_cleanup ( vcapture - > ved . ent ) ;
kfree ( vcapture ) ;
2019-02-21 08:47:28 -05:00
}
2022-06-16 11:07:45 +01:00
static void vimc_capture_unregister ( struct vimc_ent_device * ved )
2017-04-07 14:55:19 -03:00
{
2022-06-16 11:07:45 +01:00
struct vimc_capture_device * vcapture =
container_of ( ved , struct vimc_capture_device , ved ) ;
2017-04-07 14:55:19 -03:00
2022-06-16 11:07:45 +01:00
vb2_video_unregister_device ( & vcapture - > vdev ) ;
2017-04-07 14:55:19 -03:00
}
2022-06-16 11:07:45 +01:00
static void * vimc_capture_process_frame ( struct vimc_ent_device * ved ,
2019-01-21 20:05:01 -05:00
const void * frame )
2017-04-07 14:55:19 -03:00
{
2022-06-16 11:07:45 +01:00
struct vimc_capture_device * vcapture = container_of ( ved , struct vimc_capture_device ,
2017-04-07 14:55:19 -03:00
ved ) ;
2022-06-16 11:07:45 +01:00
struct vimc_capture_buffer * vimc_buf ;
2017-04-07 14:55:19 -03:00
void * vbuf ;
2022-06-16 11:07:45 +01:00
spin_lock ( & vcapture - > qlock ) ;
2017-04-07 14:55:19 -03:00
/* Get the first entry of the list */
2022-06-16 11:07:45 +01:00
vimc_buf = list_first_entry_or_null ( & vcapture - > buf_list ,
2017-04-07 14:55:19 -03:00
typeof ( * vimc_buf ) , list ) ;
if ( ! vimc_buf ) {
2022-06-16 11:07:45 +01:00
spin_unlock ( & vcapture - > qlock ) ;
2019-01-21 20:05:01 -05:00
return ERR_PTR ( - EAGAIN ) ;
2017-04-07 14:55:19 -03:00
}
/* Remove this entry from the list */
list_del ( & vimc_buf - > list ) ;
2022-06-16 11:07:45 +01:00
spin_unlock ( & vcapture - > qlock ) ;
2017-04-07 14:55:19 -03:00
/* Fill the buffer */
vimc_buf - > vb2 . vb2_buf . timestamp = ktime_get_ns ( ) ;
2022-06-16 11:07:45 +01:00
vimc_buf - > vb2 . sequence = vcapture - > sequence + + ;
vimc_buf - > vb2 . field = vcapture - > format . field ;
2017-04-07 14:55:19 -03:00
vbuf = vb2_plane_vaddr ( & vimc_buf - > vb2 . vb2_buf , 0 ) ;
2022-06-16 11:07:45 +01:00
memcpy ( vbuf , frame , vcapture - > format . sizeimage ) ;
2017-04-07 14:55:19 -03:00
/* Set it as ready */
vb2_set_plane_payload ( & vimc_buf - > vb2 . vb2_buf , 0 ,
2022-06-16 11:07:45 +01:00
vcapture - > format . sizeimage ) ;
2017-04-07 14:55:19 -03:00
vb2_buffer_done ( & vimc_buf - > vb2 . vb2_buf , VB2_BUF_STATE_DONE ) ;
2019-01-21 20:05:01 -05:00
return NULL ;
2017-04-07 14:55:19 -03:00
}
2022-06-16 11:07:45 +01:00
static struct vimc_ent_device * vimc_capture_add ( struct vimc_device * vimc ,
2020-03-31 20:45:15 +02:00
const char * vcfg_name )
2017-04-07 14:55:19 -03:00
{
2019-09-17 13:35:08 -03:00
struct v4l2_device * v4l2_dev = & vimc - > v4l2_dev ;
2019-08-08 21:27:41 -03:00
const struct vimc_pix_map * vpix ;
2022-06-16 11:07:45 +01:00
struct vimc_capture_device * vcapture ;
2017-04-07 14:55:19 -03:00
struct video_device * vdev ;
struct vb2_queue * q ;
int ret ;
2022-06-16 11:07:45 +01:00
/* Allocate the vimc_capture_device struct */
vcapture = kzalloc ( sizeof ( * vcapture ) , GFP_KERNEL ) ;
if ( ! vcapture )
2020-03-28 08:52:52 +01:00
return ERR_PTR ( - ENOMEM ) ;
2017-04-07 14:55:19 -03:00
/* Initialize the media entity */
2022-06-16 11:07:45 +01:00
vcapture - > vdev . entity . name = vcfg_name ;
vcapture - > vdev . entity . function = MEDIA_ENT_F_IO_V4L ;
vcapture - > pad . flags = MEDIA_PAD_FL_SINK ;
ret = media_entity_pads_init ( & vcapture - > vdev . entity ,
1 , & vcapture - > pad ) ;
2017-04-07 14:55:19 -03:00
if ( ret )
2022-06-16 11:07:45 +01:00
goto err_free_vcapture ;
2017-04-07 14:55:19 -03:00
/* Initialize the lock */
2022-06-16 11:07:45 +01:00
mutex_init ( & vcapture - > lock ) ;
2017-04-07 14:55:19 -03:00
/* Initialize the vb2 queue */
2022-06-16 11:07:45 +01:00
q = & vcapture - > queue ;
2017-04-07 14:55:19 -03:00
q - > type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
2021-07-30 15:18:29 +02:00
q - > io_modes = VB2_MMAP | VB2_DMABUF ;
if ( vimc_allocator = = VIMC_ALLOCATOR_VMALLOC )
q - > io_modes | = VB2_USERPTR ;
2022-06-16 11:07:45 +01:00
q - > drv_priv = vcapture ;
q - > buf_struct_size = sizeof ( struct vimc_capture_buffer ) ;
q - > ops = & vimc_capture_qops ;
2021-07-30 15:18:29 +02:00
q - > mem_ops = vimc_allocator = = VIMC_ALLOCATOR_DMA_CONTIG
? & vb2_dma_contig_memops : & vb2_vmalloc_memops ;
2017-04-07 14:55:19 -03:00
q - > timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC ;
q - > min_buffers_needed = 2 ;
2022-06-16 11:07:45 +01:00
q - > lock = & vcapture - > lock ;
2021-07-30 15:18:29 +02:00
q - > dev = v4l2_dev - > dev ;
2017-04-07 14:55:19 -03:00
ret = vb2_queue_init ( q ) ;
if ( ret ) {
2020-01-22 17:01:46 +01:00
dev_err ( vimc - > mdev . dev , " %s: vb2 queue init failed (err=%d) \n " ,
2019-09-17 13:35:08 -03:00
vcfg_name , ret ) ;
2017-04-07 14:55:19 -03:00
goto err_clean_m_ent ;
}
/* Initialize buffer list and its lock */
2022-06-16 11:07:45 +01:00
INIT_LIST_HEAD ( & vcapture - > buf_list ) ;
spin_lock_init ( & vcapture - > qlock ) ;
2017-04-07 14:55:19 -03:00
2017-06-19 14:00:17 -03:00
/* Set default frame format */
2022-06-16 11:07:45 +01:00
vcapture - > format = fmt_default ;
vpix = vimc_pix_map_by_pixelformat ( vcapture - > format . pixelformat ) ;
vcapture - > format . bytesperline = vcapture - > format . width * vpix - > bpp ;
vcapture - > format . sizeimage = vcapture - > format . bytesperline *
vcapture - > format . height ;
2017-04-07 14:55:19 -03:00
/* Fill the vimc_ent_device struct */
2022-06-16 11:07:45 +01:00
vcapture - > ved . ent = & vcapture - > vdev . entity ;
vcapture - > ved . process_frame = vimc_capture_process_frame ;
vcapture - > ved . vdev_get_format = vimc_capture_get_format ;
vcapture - > ved . dev = vimc - > mdev . dev ;
2017-04-07 14:55:19 -03:00
/* Initialize the video_device struct */
2022-06-16 11:07:45 +01:00
vdev = & vcapture - > vdev ;
2020-04-21 15:57:43 +02:00
vdev - > device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING
| V4L2_CAP_IO_MC ;
2022-06-16 11:07:45 +01:00
vdev - > entity . ops = & vimc_capture_mops ;
2020-01-22 17:01:48 +01:00
vdev - > release = video_device_release_empty ;
2022-06-16 11:07:45 +01:00
vdev - > fops = & vimc_capture_fops ;
vdev - > ioctl_ops = & vimc_capture_ioctl_ops ;
vdev - > lock = & vcapture - > lock ;
2017-04-07 14:55:19 -03:00
vdev - > queue = q ;
vdev - > v4l2_dev = v4l2_dev ;
vdev - > vfl_dir = VFL_DIR_RX ;
2019-09-17 13:35:08 -03:00
strscpy ( vdev - > name , vcfg_name , sizeof ( vdev - > name ) ) ;
2022-06-16 11:07:45 +01:00
video_set_drvdata ( vdev , & vcapture - > ved ) ;
2017-04-07 14:55:19 -03:00
/* Register the video_device with the v4l2 and the media framework */
2020-02-03 12:41:18 +01:00
ret = video_register_device ( vdev , VFL_TYPE_VIDEO , - 1 ) ;
2017-04-07 14:55:19 -03:00
if ( ret ) {
2020-01-22 17:01:46 +01:00
dev_err ( vimc - > mdev . dev , " %s: video register failed (err=%d) \n " ,
2022-06-16 11:07:45 +01:00
vcapture - > vdev . name , ret ) ;
2020-07-13 13:30:47 +02:00
goto err_clean_m_ent ;
2017-04-07 14:55:19 -03:00
}
2022-06-16 11:07:45 +01:00
return & vcapture - > ved ;
2017-04-07 14:55:19 -03:00
err_clean_m_ent :
2022-06-16 11:07:45 +01:00
media_entity_cleanup ( & vcapture - > vdev . entity ) ;
err_free_vcapture :
kfree ( vcapture ) ;
2017-04-07 14:55:19 -03:00
2020-03-28 08:52:52 +01:00
return ERR_PTR ( ret ) ;
2017-06-19 14:00:18 -03:00
}
2020-03-31 20:45:15 +02:00
2022-06-16 11:07:45 +01:00
struct vimc_ent_type vimc_capture_type = {
. add = vimc_capture_add ,
. unregister = vimc_capture_unregister ,
. release = vimc_capture_release
2020-03-31 20:45:15 +02:00
} ;