18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2005-2006 Micronas USA Inc. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/module.h> 78c2ecf20Sopenharmony_ci#include <linux/delay.h> 88c2ecf20Sopenharmony_ci#include <linux/sched.h> 98c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 108c2ecf20Sopenharmony_ci#include <linux/slab.h> 118c2ecf20Sopenharmony_ci#include <linux/fs.h> 128c2ecf20Sopenharmony_ci#include <linux/unistd.h> 138c2ecf20Sopenharmony_ci#include <linux/time.h> 148c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 158c2ecf20Sopenharmony_ci#include <linux/pagemap.h> 168c2ecf20Sopenharmony_ci#include <linux/i2c.h> 178c2ecf20Sopenharmony_ci#include <linux/mutex.h> 188c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 198c2ecf20Sopenharmony_ci#include <linux/videodev2.h> 208c2ecf20Sopenharmony_ci#include <media/v4l2-common.h> 218c2ecf20Sopenharmony_ci#include <media/v4l2-ioctl.h> 228c2ecf20Sopenharmony_ci#include <media/v4l2-subdev.h> 238c2ecf20Sopenharmony_ci#include <media/v4l2-event.h> 248c2ecf20Sopenharmony_ci#include <media/videobuf2-vmalloc.h> 258c2ecf20Sopenharmony_ci#include <media/i2c/saa7115.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include "go7007-priv.h" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define call_all(dev, o, f, args...) \ 308c2ecf20Sopenharmony_ci v4l2_device_call_until_err(dev, 0, o, f, ##args) 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic bool valid_pixelformat(u32 pixelformat) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci switch (pixelformat) { 358c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_MJPEG: 368c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_MPEG1: 378c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_MPEG2: 388c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_MPEG4: 398c2ecf20Sopenharmony_ci return true; 408c2ecf20Sopenharmony_ci default: 418c2ecf20Sopenharmony_ci return false; 428c2ecf20Sopenharmony_ci } 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic u32 get_frame_type_flag(struct go7007_buffer *vb, int format) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci u8 *ptr = vb2_plane_vaddr(&vb->vb.vb2_buf, 0); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci switch (format) { 508c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_MJPEG: 518c2ecf20Sopenharmony_ci return V4L2_BUF_FLAG_KEYFRAME; 528c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_MPEG4: 538c2ecf20Sopenharmony_ci switch ((ptr[vb->frame_offset + 4] >> 6) & 0x3) { 548c2ecf20Sopenharmony_ci case 0: 558c2ecf20Sopenharmony_ci return V4L2_BUF_FLAG_KEYFRAME; 568c2ecf20Sopenharmony_ci case 1: 578c2ecf20Sopenharmony_ci return V4L2_BUF_FLAG_PFRAME; 588c2ecf20Sopenharmony_ci case 2: 598c2ecf20Sopenharmony_ci return V4L2_BUF_FLAG_BFRAME; 608c2ecf20Sopenharmony_ci default: 618c2ecf20Sopenharmony_ci return 0; 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_MPEG1: 648c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_MPEG2: 658c2ecf20Sopenharmony_ci switch ((ptr[vb->frame_offset + 5] >> 3) & 0x7) { 668c2ecf20Sopenharmony_ci case 1: 678c2ecf20Sopenharmony_ci return V4L2_BUF_FLAG_KEYFRAME; 688c2ecf20Sopenharmony_ci case 2: 698c2ecf20Sopenharmony_ci return V4L2_BUF_FLAG_PFRAME; 708c2ecf20Sopenharmony_ci case 3: 718c2ecf20Sopenharmony_ci return V4L2_BUF_FLAG_BFRAME; 728c2ecf20Sopenharmony_ci default: 738c2ecf20Sopenharmony_ci return 0; 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci return 0; 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic void get_resolution(struct go7007 *go, int *width, int *height) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci switch (go->standard) { 838c2ecf20Sopenharmony_ci case GO7007_STD_NTSC: 848c2ecf20Sopenharmony_ci *width = 720; 858c2ecf20Sopenharmony_ci *height = 480; 868c2ecf20Sopenharmony_ci break; 878c2ecf20Sopenharmony_ci case GO7007_STD_PAL: 888c2ecf20Sopenharmony_ci *width = 720; 898c2ecf20Sopenharmony_ci *height = 576; 908c2ecf20Sopenharmony_ci break; 918c2ecf20Sopenharmony_ci case GO7007_STD_OTHER: 928c2ecf20Sopenharmony_ci default: 938c2ecf20Sopenharmony_ci *width = go->board_info->sensor_width; 948c2ecf20Sopenharmony_ci *height = go->board_info->sensor_height; 958c2ecf20Sopenharmony_ci break; 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic void set_formatting(struct go7007 *go) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci if (go->format == V4L2_PIX_FMT_MJPEG) { 1028c2ecf20Sopenharmony_ci go->pali = 0; 1038c2ecf20Sopenharmony_ci go->aspect_ratio = GO7007_RATIO_1_1; 1048c2ecf20Sopenharmony_ci go->gop_size = 0; 1058c2ecf20Sopenharmony_ci go->ipb = 0; 1068c2ecf20Sopenharmony_ci go->closed_gop = 0; 1078c2ecf20Sopenharmony_ci go->repeat_seqhead = 0; 1088c2ecf20Sopenharmony_ci go->seq_header_enable = 0; 1098c2ecf20Sopenharmony_ci go->gop_header_enable = 0; 1108c2ecf20Sopenharmony_ci go->dvd_mode = 0; 1118c2ecf20Sopenharmony_ci return; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci switch (go->format) { 1158c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_MPEG1: 1168c2ecf20Sopenharmony_ci go->pali = 0; 1178c2ecf20Sopenharmony_ci break; 1188c2ecf20Sopenharmony_ci default: 1198c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_MPEG2: 1208c2ecf20Sopenharmony_ci go->pali = 0x48; 1218c2ecf20Sopenharmony_ci break; 1228c2ecf20Sopenharmony_ci case V4L2_PIX_FMT_MPEG4: 1238c2ecf20Sopenharmony_ci /* For future reference: this is the list of MPEG4 1248c2ecf20Sopenharmony_ci * profiles that are available, although they are 1258c2ecf20Sopenharmony_ci * untested: 1268c2ecf20Sopenharmony_ci * 1278c2ecf20Sopenharmony_ci * Profile pali 1288c2ecf20Sopenharmony_ci * -------------- ---- 1298c2ecf20Sopenharmony_ci * PROFILE_S_L0 0x08 1308c2ecf20Sopenharmony_ci * PROFILE_S_L1 0x01 1318c2ecf20Sopenharmony_ci * PROFILE_S_L2 0x02 1328c2ecf20Sopenharmony_ci * PROFILE_S_L3 0x03 1338c2ecf20Sopenharmony_ci * PROFILE_ARTS_L1 0x91 1348c2ecf20Sopenharmony_ci * PROFILE_ARTS_L2 0x92 1358c2ecf20Sopenharmony_ci * PROFILE_ARTS_L3 0x93 1368c2ecf20Sopenharmony_ci * PROFILE_ARTS_L4 0x94 1378c2ecf20Sopenharmony_ci * PROFILE_AS_L0 0xf0 1388c2ecf20Sopenharmony_ci * PROFILE_AS_L1 0xf1 1398c2ecf20Sopenharmony_ci * PROFILE_AS_L2 0xf2 1408c2ecf20Sopenharmony_ci * PROFILE_AS_L3 0xf3 1418c2ecf20Sopenharmony_ci * PROFILE_AS_L4 0xf4 1428c2ecf20Sopenharmony_ci * PROFILE_AS_L5 0xf5 1438c2ecf20Sopenharmony_ci */ 1448c2ecf20Sopenharmony_ci go->pali = 0xf5; 1458c2ecf20Sopenharmony_ci break; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci go->gop_size = v4l2_ctrl_g_ctrl(go->mpeg_video_gop_size); 1488c2ecf20Sopenharmony_ci go->closed_gop = v4l2_ctrl_g_ctrl(go->mpeg_video_gop_closure); 1498c2ecf20Sopenharmony_ci go->ipb = v4l2_ctrl_g_ctrl(go->mpeg_video_b_frames) != 0; 1508c2ecf20Sopenharmony_ci go->bitrate = v4l2_ctrl_g_ctrl(go->mpeg_video_bitrate); 1518c2ecf20Sopenharmony_ci go->repeat_seqhead = v4l2_ctrl_g_ctrl(go->mpeg_video_rep_seqheader); 1528c2ecf20Sopenharmony_ci go->gop_header_enable = 1; 1538c2ecf20Sopenharmony_ci go->dvd_mode = 0; 1548c2ecf20Sopenharmony_ci if (go->format == V4L2_PIX_FMT_MPEG2) 1558c2ecf20Sopenharmony_ci go->dvd_mode = 1568c2ecf20Sopenharmony_ci go->bitrate == 9800000 && 1578c2ecf20Sopenharmony_ci go->gop_size == 15 && 1588c2ecf20Sopenharmony_ci go->ipb == 0 && 1598c2ecf20Sopenharmony_ci go->repeat_seqhead == 1 && 1608c2ecf20Sopenharmony_ci go->closed_gop; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci switch (v4l2_ctrl_g_ctrl(go->mpeg_video_aspect_ratio)) { 1638c2ecf20Sopenharmony_ci default: 1648c2ecf20Sopenharmony_ci case V4L2_MPEG_VIDEO_ASPECT_1x1: 1658c2ecf20Sopenharmony_ci go->aspect_ratio = GO7007_RATIO_1_1; 1668c2ecf20Sopenharmony_ci break; 1678c2ecf20Sopenharmony_ci case V4L2_MPEG_VIDEO_ASPECT_4x3: 1688c2ecf20Sopenharmony_ci go->aspect_ratio = GO7007_RATIO_4_3; 1698c2ecf20Sopenharmony_ci break; 1708c2ecf20Sopenharmony_ci case V4L2_MPEG_VIDEO_ASPECT_16x9: 1718c2ecf20Sopenharmony_ci go->aspect_ratio = GO7007_RATIO_16_9; 1728c2ecf20Sopenharmony_ci break; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci int sensor_height = 0, sensor_width = 0; 1798c2ecf20Sopenharmony_ci int width, height; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci if (fmt != NULL && !valid_pixelformat(fmt->fmt.pix.pixelformat)) 1828c2ecf20Sopenharmony_ci return -EINVAL; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci get_resolution(go, &sensor_width, &sensor_height); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci if (fmt == NULL) { 1878c2ecf20Sopenharmony_ci width = sensor_width; 1888c2ecf20Sopenharmony_ci height = sensor_height; 1898c2ecf20Sopenharmony_ci } else if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING) { 1908c2ecf20Sopenharmony_ci if (fmt->fmt.pix.width > sensor_width) 1918c2ecf20Sopenharmony_ci width = sensor_width; 1928c2ecf20Sopenharmony_ci else if (fmt->fmt.pix.width < 144) 1938c2ecf20Sopenharmony_ci width = 144; 1948c2ecf20Sopenharmony_ci else 1958c2ecf20Sopenharmony_ci width = fmt->fmt.pix.width & ~0x0f; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci if (fmt->fmt.pix.height > sensor_height) 1988c2ecf20Sopenharmony_ci height = sensor_height; 1998c2ecf20Sopenharmony_ci else if (fmt->fmt.pix.height < 96) 2008c2ecf20Sopenharmony_ci height = 96; 2018c2ecf20Sopenharmony_ci else 2028c2ecf20Sopenharmony_ci height = fmt->fmt.pix.height & ~0x0f; 2038c2ecf20Sopenharmony_ci } else { 2048c2ecf20Sopenharmony_ci width = fmt->fmt.pix.width; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci if (width <= sensor_width / 4) { 2078c2ecf20Sopenharmony_ci width = sensor_width / 4; 2088c2ecf20Sopenharmony_ci height = sensor_height / 4; 2098c2ecf20Sopenharmony_ci } else if (width <= sensor_width / 2) { 2108c2ecf20Sopenharmony_ci width = sensor_width / 2; 2118c2ecf20Sopenharmony_ci height = sensor_height / 2; 2128c2ecf20Sopenharmony_ci } else { 2138c2ecf20Sopenharmony_ci width = sensor_width; 2148c2ecf20Sopenharmony_ci height = sensor_height; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci width &= ~0xf; 2178c2ecf20Sopenharmony_ci height &= ~0xf; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (fmt != NULL) { 2218c2ecf20Sopenharmony_ci u32 pixelformat = fmt->fmt.pix.pixelformat; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci memset(fmt, 0, sizeof(*fmt)); 2248c2ecf20Sopenharmony_ci fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 2258c2ecf20Sopenharmony_ci fmt->fmt.pix.width = width; 2268c2ecf20Sopenharmony_ci fmt->fmt.pix.height = height; 2278c2ecf20Sopenharmony_ci fmt->fmt.pix.pixelformat = pixelformat; 2288c2ecf20Sopenharmony_ci fmt->fmt.pix.field = V4L2_FIELD_NONE; 2298c2ecf20Sopenharmony_ci fmt->fmt.pix.bytesperline = 0; 2308c2ecf20Sopenharmony_ci fmt->fmt.pix.sizeimage = GO7007_BUF_SIZE; 2318c2ecf20Sopenharmony_ci fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci if (try) 2358c2ecf20Sopenharmony_ci return 0; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci if (fmt) 2388c2ecf20Sopenharmony_ci go->format = fmt->fmt.pix.pixelformat; 2398c2ecf20Sopenharmony_ci go->width = width; 2408c2ecf20Sopenharmony_ci go->height = height; 2418c2ecf20Sopenharmony_ci go->encoder_h_offset = go->board_info->sensor_h_offset; 2428c2ecf20Sopenharmony_ci go->encoder_v_offset = go->board_info->sensor_v_offset; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING) { 2458c2ecf20Sopenharmony_ci struct v4l2_subdev_format format = { 2468c2ecf20Sopenharmony_ci .which = V4L2_SUBDEV_FORMAT_ACTIVE, 2478c2ecf20Sopenharmony_ci }; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci format.format.code = MEDIA_BUS_FMT_FIXED; 2508c2ecf20Sopenharmony_ci format.format.width = fmt ? fmt->fmt.pix.width : width; 2518c2ecf20Sopenharmony_ci format.format.height = height; 2528c2ecf20Sopenharmony_ci go->encoder_h_halve = 0; 2538c2ecf20Sopenharmony_ci go->encoder_v_halve = 0; 2548c2ecf20Sopenharmony_ci go->encoder_subsample = 0; 2558c2ecf20Sopenharmony_ci call_all(&go->v4l2_dev, pad, set_fmt, NULL, &format); 2568c2ecf20Sopenharmony_ci } else { 2578c2ecf20Sopenharmony_ci if (width <= sensor_width / 4) { 2588c2ecf20Sopenharmony_ci go->encoder_h_halve = 1; 2598c2ecf20Sopenharmony_ci go->encoder_v_halve = 1; 2608c2ecf20Sopenharmony_ci go->encoder_subsample = 1; 2618c2ecf20Sopenharmony_ci } else if (width <= sensor_width / 2) { 2628c2ecf20Sopenharmony_ci go->encoder_h_halve = 1; 2638c2ecf20Sopenharmony_ci go->encoder_v_halve = 1; 2648c2ecf20Sopenharmony_ci go->encoder_subsample = 0; 2658c2ecf20Sopenharmony_ci } else { 2668c2ecf20Sopenharmony_ci go->encoder_h_halve = 0; 2678c2ecf20Sopenharmony_ci go->encoder_v_halve = 0; 2688c2ecf20Sopenharmony_ci go->encoder_subsample = 0; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci return 0; 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_cistatic int vidioc_querycap(struct file *file, void *priv, 2758c2ecf20Sopenharmony_ci struct v4l2_capability *cap) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci struct go7007 *go = video_drvdata(file); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci strscpy(cap->driver, "go7007", sizeof(cap->driver)); 2808c2ecf20Sopenharmony_ci strscpy(cap->card, go->name, sizeof(cap->card)); 2818c2ecf20Sopenharmony_ci strscpy(cap->bus_info, go->bus_info, sizeof(cap->bus_info)); 2828c2ecf20Sopenharmony_ci return 0; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, 2868c2ecf20Sopenharmony_ci struct v4l2_fmtdesc *fmt) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci switch (fmt->index) { 2898c2ecf20Sopenharmony_ci case 0: 2908c2ecf20Sopenharmony_ci fmt->pixelformat = V4L2_PIX_FMT_MJPEG; 2918c2ecf20Sopenharmony_ci break; 2928c2ecf20Sopenharmony_ci case 1: 2938c2ecf20Sopenharmony_ci fmt->pixelformat = V4L2_PIX_FMT_MPEG1; 2948c2ecf20Sopenharmony_ci break; 2958c2ecf20Sopenharmony_ci case 2: 2968c2ecf20Sopenharmony_ci fmt->pixelformat = V4L2_PIX_FMT_MPEG2; 2978c2ecf20Sopenharmony_ci break; 2988c2ecf20Sopenharmony_ci case 3: 2998c2ecf20Sopenharmony_ci fmt->pixelformat = V4L2_PIX_FMT_MPEG4; 3008c2ecf20Sopenharmony_ci break; 3018c2ecf20Sopenharmony_ci default: 3028c2ecf20Sopenharmony_ci return -EINVAL; 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci return 0; 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic int vidioc_g_fmt_vid_cap(struct file *file, void *priv, 3088c2ecf20Sopenharmony_ci struct v4l2_format *fmt) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci struct go7007 *go = video_drvdata(file); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 3138c2ecf20Sopenharmony_ci fmt->fmt.pix.width = go->width; 3148c2ecf20Sopenharmony_ci fmt->fmt.pix.height = go->height; 3158c2ecf20Sopenharmony_ci fmt->fmt.pix.pixelformat = go->format; 3168c2ecf20Sopenharmony_ci fmt->fmt.pix.field = V4L2_FIELD_NONE; 3178c2ecf20Sopenharmony_ci fmt->fmt.pix.bytesperline = 0; 3188c2ecf20Sopenharmony_ci fmt->fmt.pix.sizeimage = GO7007_BUF_SIZE; 3198c2ecf20Sopenharmony_ci fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci return 0; 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_cistatic int vidioc_try_fmt_vid_cap(struct file *file, void *priv, 3258c2ecf20Sopenharmony_ci struct v4l2_format *fmt) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci struct go7007 *go = video_drvdata(file); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci return set_capture_size(go, fmt, 1); 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic int vidioc_s_fmt_vid_cap(struct file *file, void *priv, 3338c2ecf20Sopenharmony_ci struct v4l2_format *fmt) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci struct go7007 *go = video_drvdata(file); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci if (vb2_is_busy(&go->vidq)) 3388c2ecf20Sopenharmony_ci return -EBUSY; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci return set_capture_size(go, fmt, 0); 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_cistatic int go7007_queue_setup(struct vb2_queue *q, 3448c2ecf20Sopenharmony_ci unsigned int *num_buffers, unsigned int *num_planes, 3458c2ecf20Sopenharmony_ci unsigned int sizes[], struct device *alloc_devs[]) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci sizes[0] = GO7007_BUF_SIZE; 3488c2ecf20Sopenharmony_ci *num_planes = 1; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci if (*num_buffers < 2) 3518c2ecf20Sopenharmony_ci *num_buffers = 2; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci return 0; 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistatic void go7007_buf_queue(struct vb2_buffer *vb) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci struct vb2_queue *vq = vb->vb2_queue; 3598c2ecf20Sopenharmony_ci struct go7007 *go = vb2_get_drv_priv(vq); 3608c2ecf20Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 3618c2ecf20Sopenharmony_ci struct go7007_buffer *go7007_vb = 3628c2ecf20Sopenharmony_ci container_of(vbuf, struct go7007_buffer, vb); 3638c2ecf20Sopenharmony_ci unsigned long flags; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci spin_lock_irqsave(&go->spinlock, flags); 3668c2ecf20Sopenharmony_ci list_add_tail(&go7007_vb->list, &go->vidq_active); 3678c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&go->spinlock, flags); 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic int go7007_buf_prepare(struct vb2_buffer *vb) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 3738c2ecf20Sopenharmony_ci struct go7007_buffer *go7007_vb = 3748c2ecf20Sopenharmony_ci container_of(vbuf, struct go7007_buffer, vb); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci go7007_vb->modet_active = 0; 3778c2ecf20Sopenharmony_ci go7007_vb->frame_offset = 0; 3788c2ecf20Sopenharmony_ci vb->planes[0].bytesused = 0; 3798c2ecf20Sopenharmony_ci return 0; 3808c2ecf20Sopenharmony_ci} 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_cistatic void go7007_buf_finish(struct vb2_buffer *vb) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci struct vb2_queue *vq = vb->vb2_queue; 3858c2ecf20Sopenharmony_ci struct go7007 *go = vb2_get_drv_priv(vq); 3868c2ecf20Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 3878c2ecf20Sopenharmony_ci struct go7007_buffer *go7007_vb = 3888c2ecf20Sopenharmony_ci container_of(vbuf, struct go7007_buffer, vb); 3898c2ecf20Sopenharmony_ci u32 frame_type_flag = get_frame_type_flag(go7007_vb, go->format); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci vbuf->flags &= ~(V4L2_BUF_FLAG_KEYFRAME | V4L2_BUF_FLAG_BFRAME | 3928c2ecf20Sopenharmony_ci V4L2_BUF_FLAG_PFRAME); 3938c2ecf20Sopenharmony_ci vbuf->flags |= frame_type_flag; 3948c2ecf20Sopenharmony_ci vbuf->field = V4L2_FIELD_NONE; 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cistatic int go7007_start_streaming(struct vb2_queue *q, unsigned int count) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci struct go7007 *go = vb2_get_drv_priv(q); 4008c2ecf20Sopenharmony_ci int ret; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci set_formatting(go); 4038c2ecf20Sopenharmony_ci mutex_lock(&go->hw_lock); 4048c2ecf20Sopenharmony_ci go->next_seq = 0; 4058c2ecf20Sopenharmony_ci go->active_buf = NULL; 4068c2ecf20Sopenharmony_ci go->modet_event_status = 0; 4078c2ecf20Sopenharmony_ci q->streaming = 1; 4088c2ecf20Sopenharmony_ci if (go7007_start_encoder(go) < 0) 4098c2ecf20Sopenharmony_ci ret = -EIO; 4108c2ecf20Sopenharmony_ci else 4118c2ecf20Sopenharmony_ci ret = 0; 4128c2ecf20Sopenharmony_ci mutex_unlock(&go->hw_lock); 4138c2ecf20Sopenharmony_ci if (ret) { 4148c2ecf20Sopenharmony_ci q->streaming = 0; 4158c2ecf20Sopenharmony_ci return ret; 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci call_all(&go->v4l2_dev, video, s_stream, 1); 4188c2ecf20Sopenharmony_ci v4l2_ctrl_grab(go->mpeg_video_gop_size, true); 4198c2ecf20Sopenharmony_ci v4l2_ctrl_grab(go->mpeg_video_gop_closure, true); 4208c2ecf20Sopenharmony_ci v4l2_ctrl_grab(go->mpeg_video_bitrate, true); 4218c2ecf20Sopenharmony_ci v4l2_ctrl_grab(go->mpeg_video_aspect_ratio, true); 4228c2ecf20Sopenharmony_ci /* Turn on Capture LED */ 4238c2ecf20Sopenharmony_ci if (go->board_id == GO7007_BOARDID_ADS_USBAV_709) 4248c2ecf20Sopenharmony_ci go7007_write_addr(go, 0x3c82, 0x0005); 4258c2ecf20Sopenharmony_ci return ret; 4268c2ecf20Sopenharmony_ci} 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_cistatic void go7007_stop_streaming(struct vb2_queue *q) 4298c2ecf20Sopenharmony_ci{ 4308c2ecf20Sopenharmony_ci struct go7007 *go = vb2_get_drv_priv(q); 4318c2ecf20Sopenharmony_ci unsigned long flags; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci q->streaming = 0; 4348c2ecf20Sopenharmony_ci go7007_stream_stop(go); 4358c2ecf20Sopenharmony_ci mutex_lock(&go->hw_lock); 4368c2ecf20Sopenharmony_ci go7007_reset_encoder(go); 4378c2ecf20Sopenharmony_ci mutex_unlock(&go->hw_lock); 4388c2ecf20Sopenharmony_ci call_all(&go->v4l2_dev, video, s_stream, 0); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci spin_lock_irqsave(&go->spinlock, flags); 4418c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&go->vidq_active); 4428c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&go->spinlock, flags); 4438c2ecf20Sopenharmony_ci v4l2_ctrl_grab(go->mpeg_video_gop_size, false); 4448c2ecf20Sopenharmony_ci v4l2_ctrl_grab(go->mpeg_video_gop_closure, false); 4458c2ecf20Sopenharmony_ci v4l2_ctrl_grab(go->mpeg_video_bitrate, false); 4468c2ecf20Sopenharmony_ci v4l2_ctrl_grab(go->mpeg_video_aspect_ratio, false); 4478c2ecf20Sopenharmony_ci /* Turn on Capture LED */ 4488c2ecf20Sopenharmony_ci if (go->board_id == GO7007_BOARDID_ADS_USBAV_709) 4498c2ecf20Sopenharmony_ci go7007_write_addr(go, 0x3c82, 0x000d); 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_cistatic const struct vb2_ops go7007_video_qops = { 4538c2ecf20Sopenharmony_ci .queue_setup = go7007_queue_setup, 4548c2ecf20Sopenharmony_ci .buf_queue = go7007_buf_queue, 4558c2ecf20Sopenharmony_ci .buf_prepare = go7007_buf_prepare, 4568c2ecf20Sopenharmony_ci .buf_finish = go7007_buf_finish, 4578c2ecf20Sopenharmony_ci .start_streaming = go7007_start_streaming, 4588c2ecf20Sopenharmony_ci .stop_streaming = go7007_stop_streaming, 4598c2ecf20Sopenharmony_ci .wait_prepare = vb2_ops_wait_prepare, 4608c2ecf20Sopenharmony_ci .wait_finish = vb2_ops_wait_finish, 4618c2ecf20Sopenharmony_ci}; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_cistatic int vidioc_g_parm(struct file *filp, void *priv, 4648c2ecf20Sopenharmony_ci struct v4l2_streamparm *parm) 4658c2ecf20Sopenharmony_ci{ 4668c2ecf20Sopenharmony_ci struct go7007 *go = video_drvdata(filp); 4678c2ecf20Sopenharmony_ci struct v4l2_fract timeperframe = { 4688c2ecf20Sopenharmony_ci .numerator = 1001 * go->fps_scale, 4698c2ecf20Sopenharmony_ci .denominator = go->sensor_framerate, 4708c2ecf20Sopenharmony_ci }; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 4738c2ecf20Sopenharmony_ci return -EINVAL; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci parm->parm.capture.readbuffers = 2; 4768c2ecf20Sopenharmony_ci parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; 4778c2ecf20Sopenharmony_ci parm->parm.capture.timeperframe = timeperframe; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci return 0; 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic int vidioc_s_parm(struct file *filp, void *priv, 4838c2ecf20Sopenharmony_ci struct v4l2_streamparm *parm) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci struct go7007 *go = video_drvdata(filp); 4868c2ecf20Sopenharmony_ci unsigned int n, d; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 4898c2ecf20Sopenharmony_ci return -EINVAL; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci n = go->sensor_framerate * 4928c2ecf20Sopenharmony_ci parm->parm.capture.timeperframe.numerator; 4938c2ecf20Sopenharmony_ci d = 1001 * parm->parm.capture.timeperframe.denominator; 4948c2ecf20Sopenharmony_ci if (n != 0 && d != 0 && n > d) 4958c2ecf20Sopenharmony_ci go->fps_scale = (n + d/2) / d; 4968c2ecf20Sopenharmony_ci else 4978c2ecf20Sopenharmony_ci go->fps_scale = 1; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci return vidioc_g_parm(filp, priv, parm); 5008c2ecf20Sopenharmony_ci} 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci/* VIDIOC_ENUMSTD on go7007 were used for enumerating the supported fps and 5038c2ecf20Sopenharmony_ci its resolution, when the device is not connected to TV. 5048c2ecf20Sopenharmony_ci This is were an API abuse, probably used by the lack of specific IOCTL's to 5058c2ecf20Sopenharmony_ci enumerate it, by the time the driver was written. 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci However, since kernel 2.6.19, two new ioctls (VIDIOC_ENUM_FRAMEINTERVALS 5088c2ecf20Sopenharmony_ci and VIDIOC_ENUM_FRAMESIZES) were added for this purpose. 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci The two functions below implement the newer ioctls 5118c2ecf20Sopenharmony_ci*/ 5128c2ecf20Sopenharmony_cistatic int vidioc_enum_framesizes(struct file *filp, void *priv, 5138c2ecf20Sopenharmony_ci struct v4l2_frmsizeenum *fsize) 5148c2ecf20Sopenharmony_ci{ 5158c2ecf20Sopenharmony_ci struct go7007 *go = video_drvdata(filp); 5168c2ecf20Sopenharmony_ci int width, height; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci if (fsize->index > 2) 5198c2ecf20Sopenharmony_ci return -EINVAL; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci if (!valid_pixelformat(fsize->pixel_format)) 5228c2ecf20Sopenharmony_ci return -EINVAL; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci get_resolution(go, &width, &height); 5258c2ecf20Sopenharmony_ci fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; 5268c2ecf20Sopenharmony_ci fsize->discrete.width = (width >> fsize->index) & ~0xf; 5278c2ecf20Sopenharmony_ci fsize->discrete.height = (height >> fsize->index) & ~0xf; 5288c2ecf20Sopenharmony_ci return 0; 5298c2ecf20Sopenharmony_ci} 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_cistatic int vidioc_enum_frameintervals(struct file *filp, void *priv, 5328c2ecf20Sopenharmony_ci struct v4l2_frmivalenum *fival) 5338c2ecf20Sopenharmony_ci{ 5348c2ecf20Sopenharmony_ci struct go7007 *go = video_drvdata(filp); 5358c2ecf20Sopenharmony_ci int width, height; 5368c2ecf20Sopenharmony_ci int i; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci if (fival->index > 4) 5398c2ecf20Sopenharmony_ci return -EINVAL; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci if (!valid_pixelformat(fival->pixel_format)) 5428c2ecf20Sopenharmony_ci return -EINVAL; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci if (!(go->board_info->sensor_flags & GO7007_SENSOR_SCALING)) { 5458c2ecf20Sopenharmony_ci get_resolution(go, &width, &height); 5468c2ecf20Sopenharmony_ci for (i = 0; i <= 2; i++) 5478c2ecf20Sopenharmony_ci if (fival->width == ((width >> i) & ~0xf) && 5488c2ecf20Sopenharmony_ci fival->height == ((height >> i) & ~0xf)) 5498c2ecf20Sopenharmony_ci break; 5508c2ecf20Sopenharmony_ci if (i > 2) 5518c2ecf20Sopenharmony_ci return -EINVAL; 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; 5548c2ecf20Sopenharmony_ci fival->discrete.numerator = 1001 * (fival->index + 1); 5558c2ecf20Sopenharmony_ci fival->discrete.denominator = go->sensor_framerate; 5568c2ecf20Sopenharmony_ci return 0; 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_cistatic int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std) 5608c2ecf20Sopenharmony_ci{ 5618c2ecf20Sopenharmony_ci struct go7007 *go = video_drvdata(file); 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci *std = go->std; 5648c2ecf20Sopenharmony_ci return 0; 5658c2ecf20Sopenharmony_ci} 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_cistatic int go7007_s_std(struct go7007 *go) 5688c2ecf20Sopenharmony_ci{ 5698c2ecf20Sopenharmony_ci if (go->std & V4L2_STD_625_50) { 5708c2ecf20Sopenharmony_ci go->standard = GO7007_STD_PAL; 5718c2ecf20Sopenharmony_ci go->sensor_framerate = 25025; 5728c2ecf20Sopenharmony_ci } else { 5738c2ecf20Sopenharmony_ci go->standard = GO7007_STD_NTSC; 5748c2ecf20Sopenharmony_ci go->sensor_framerate = 30000; 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci call_all(&go->v4l2_dev, video, s_std, go->std); 5788c2ecf20Sopenharmony_ci set_capture_size(go, NULL, 0); 5798c2ecf20Sopenharmony_ci return 0; 5808c2ecf20Sopenharmony_ci} 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_cistatic int vidioc_s_std(struct file *file, void *priv, v4l2_std_id std) 5838c2ecf20Sopenharmony_ci{ 5848c2ecf20Sopenharmony_ci struct go7007 *go = video_drvdata(file); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci if (vb2_is_busy(&go->vidq)) 5878c2ecf20Sopenharmony_ci return -EBUSY; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci go->std = std; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci return go7007_s_std(go); 5928c2ecf20Sopenharmony_ci} 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_cistatic int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *std) 5958c2ecf20Sopenharmony_ci{ 5968c2ecf20Sopenharmony_ci struct go7007 *go = video_drvdata(file); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci return call_all(&go->v4l2_dev, video, querystd, std); 5998c2ecf20Sopenharmony_ci} 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_cistatic int vidioc_enum_input(struct file *file, void *priv, 6028c2ecf20Sopenharmony_ci struct v4l2_input *inp) 6038c2ecf20Sopenharmony_ci{ 6048c2ecf20Sopenharmony_ci struct go7007 *go = video_drvdata(file); 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci if (inp->index >= go->board_info->num_inputs) 6078c2ecf20Sopenharmony_ci return -EINVAL; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci strscpy(inp->name, go->board_info->inputs[inp->index].name, 6108c2ecf20Sopenharmony_ci sizeof(inp->name)); 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci /* If this board has a tuner, it will be the first input */ 6138c2ecf20Sopenharmony_ci if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) && 6148c2ecf20Sopenharmony_ci inp->index == 0) 6158c2ecf20Sopenharmony_ci inp->type = V4L2_INPUT_TYPE_TUNER; 6168c2ecf20Sopenharmony_ci else 6178c2ecf20Sopenharmony_ci inp->type = V4L2_INPUT_TYPE_CAMERA; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci if (go->board_info->num_aud_inputs) 6208c2ecf20Sopenharmony_ci inp->audioset = (1 << go->board_info->num_aud_inputs) - 1; 6218c2ecf20Sopenharmony_ci else 6228c2ecf20Sopenharmony_ci inp->audioset = 0; 6238c2ecf20Sopenharmony_ci inp->tuner = 0; 6248c2ecf20Sopenharmony_ci if (go->board_info->sensor_flags & GO7007_SENSOR_TV) 6258c2ecf20Sopenharmony_ci inp->std = video_devdata(file)->tvnorms; 6268c2ecf20Sopenharmony_ci else 6278c2ecf20Sopenharmony_ci inp->std = 0; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci return 0; 6308c2ecf20Sopenharmony_ci} 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_cistatic int vidioc_g_input(struct file *file, void *priv, unsigned int *input) 6348c2ecf20Sopenharmony_ci{ 6358c2ecf20Sopenharmony_ci struct go7007 *go = video_drvdata(file); 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci *input = go->input; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci return 0; 6408c2ecf20Sopenharmony_ci} 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_cistatic int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *a) 6438c2ecf20Sopenharmony_ci{ 6448c2ecf20Sopenharmony_ci struct go7007 *go = video_drvdata(file); 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci if (a->index >= go->board_info->num_aud_inputs) 6478c2ecf20Sopenharmony_ci return -EINVAL; 6488c2ecf20Sopenharmony_ci strscpy(a->name, go->board_info->aud_inputs[a->index].name, 6498c2ecf20Sopenharmony_ci sizeof(a->name)); 6508c2ecf20Sopenharmony_ci a->capability = V4L2_AUDCAP_STEREO; 6518c2ecf20Sopenharmony_ci return 0; 6528c2ecf20Sopenharmony_ci} 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_cistatic int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a) 6558c2ecf20Sopenharmony_ci{ 6568c2ecf20Sopenharmony_ci struct go7007 *go = video_drvdata(file); 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci a->index = go->aud_input; 6598c2ecf20Sopenharmony_ci strscpy(a->name, go->board_info->aud_inputs[go->aud_input].name, 6608c2ecf20Sopenharmony_ci sizeof(a->name)); 6618c2ecf20Sopenharmony_ci a->capability = V4L2_AUDCAP_STEREO; 6628c2ecf20Sopenharmony_ci return 0; 6638c2ecf20Sopenharmony_ci} 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_cistatic int vidioc_s_audio(struct file *file, void *fh, 6668c2ecf20Sopenharmony_ci const struct v4l2_audio *a) 6678c2ecf20Sopenharmony_ci{ 6688c2ecf20Sopenharmony_ci struct go7007 *go = video_drvdata(file); 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci if (a->index >= go->board_info->num_aud_inputs) 6718c2ecf20Sopenharmony_ci return -EINVAL; 6728c2ecf20Sopenharmony_ci go->aud_input = a->index; 6738c2ecf20Sopenharmony_ci v4l2_subdev_call(go->sd_audio, audio, s_routing, 6748c2ecf20Sopenharmony_ci go->board_info->aud_inputs[go->aud_input].audio_input, 0, 0); 6758c2ecf20Sopenharmony_ci return 0; 6768c2ecf20Sopenharmony_ci} 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_cistatic void go7007_s_input(struct go7007 *go) 6798c2ecf20Sopenharmony_ci{ 6808c2ecf20Sopenharmony_ci unsigned int input = go->input; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci v4l2_subdev_call(go->sd_video, video, s_routing, 6838c2ecf20Sopenharmony_ci go->board_info->inputs[input].video_input, 0, 6848c2ecf20Sopenharmony_ci go->board_info->video_config); 6858c2ecf20Sopenharmony_ci if (go->board_info->num_aud_inputs) { 6868c2ecf20Sopenharmony_ci int aud_input = go->board_info->inputs[input].audio_index; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci v4l2_subdev_call(go->sd_audio, audio, s_routing, 6898c2ecf20Sopenharmony_ci go->board_info->aud_inputs[aud_input].audio_input, 0, 0); 6908c2ecf20Sopenharmony_ci go->aud_input = aud_input; 6918c2ecf20Sopenharmony_ci } 6928c2ecf20Sopenharmony_ci} 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_cistatic int vidioc_s_input(struct file *file, void *priv, unsigned int input) 6958c2ecf20Sopenharmony_ci{ 6968c2ecf20Sopenharmony_ci struct go7007 *go = video_drvdata(file); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci if (input >= go->board_info->num_inputs) 6998c2ecf20Sopenharmony_ci return -EINVAL; 7008c2ecf20Sopenharmony_ci if (vb2_is_busy(&go->vidq)) 7018c2ecf20Sopenharmony_ci return -EBUSY; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci go->input = input; 7048c2ecf20Sopenharmony_ci go7007_s_input(go); 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci return 0; 7078c2ecf20Sopenharmony_ci} 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_cistatic int vidioc_g_tuner(struct file *file, void *priv, 7108c2ecf20Sopenharmony_ci struct v4l2_tuner *t) 7118c2ecf20Sopenharmony_ci{ 7128c2ecf20Sopenharmony_ci struct go7007 *go = video_drvdata(file); 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci if (t->index != 0) 7158c2ecf20Sopenharmony_ci return -EINVAL; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci strscpy(t->name, "Tuner", sizeof(t->name)); 7188c2ecf20Sopenharmony_ci return call_all(&go->v4l2_dev, tuner, g_tuner, t); 7198c2ecf20Sopenharmony_ci} 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_cistatic int vidioc_s_tuner(struct file *file, void *priv, 7228c2ecf20Sopenharmony_ci const struct v4l2_tuner *t) 7238c2ecf20Sopenharmony_ci{ 7248c2ecf20Sopenharmony_ci struct go7007 *go = video_drvdata(file); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci if (t->index != 0) 7278c2ecf20Sopenharmony_ci return -EINVAL; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci return call_all(&go->v4l2_dev, tuner, s_tuner, t); 7308c2ecf20Sopenharmony_ci} 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_cistatic int vidioc_g_frequency(struct file *file, void *priv, 7338c2ecf20Sopenharmony_ci struct v4l2_frequency *f) 7348c2ecf20Sopenharmony_ci{ 7358c2ecf20Sopenharmony_ci struct go7007 *go = video_drvdata(file); 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci if (f->tuner) 7388c2ecf20Sopenharmony_ci return -EINVAL; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci return call_all(&go->v4l2_dev, tuner, g_frequency, f); 7418c2ecf20Sopenharmony_ci} 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_cistatic int vidioc_s_frequency(struct file *file, void *priv, 7448c2ecf20Sopenharmony_ci const struct v4l2_frequency *f) 7458c2ecf20Sopenharmony_ci{ 7468c2ecf20Sopenharmony_ci struct go7007 *go = video_drvdata(file); 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci if (f->tuner) 7498c2ecf20Sopenharmony_ci return -EINVAL; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci return call_all(&go->v4l2_dev, tuner, s_frequency, f); 7528c2ecf20Sopenharmony_ci} 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_cistatic int vidioc_log_status(struct file *file, void *priv) 7558c2ecf20Sopenharmony_ci{ 7568c2ecf20Sopenharmony_ci struct go7007 *go = video_drvdata(file); 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci v4l2_ctrl_log_status(file, priv); 7598c2ecf20Sopenharmony_ci return call_all(&go->v4l2_dev, core, log_status); 7608c2ecf20Sopenharmony_ci} 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_cistatic int vidioc_subscribe_event(struct v4l2_fh *fh, 7638c2ecf20Sopenharmony_ci const struct v4l2_event_subscription *sub) 7648c2ecf20Sopenharmony_ci{ 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci switch (sub->type) { 7678c2ecf20Sopenharmony_ci case V4L2_EVENT_MOTION_DET: 7688c2ecf20Sopenharmony_ci /* Allow for up to 30 events (1 second for NTSC) to be 7698c2ecf20Sopenharmony_ci * stored. */ 7708c2ecf20Sopenharmony_ci return v4l2_event_subscribe(fh, sub, 30, NULL); 7718c2ecf20Sopenharmony_ci default: 7728c2ecf20Sopenharmony_ci return v4l2_ctrl_subscribe_event(fh, sub); 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci} 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_cistatic int go7007_s_ctrl(struct v4l2_ctrl *ctrl) 7788c2ecf20Sopenharmony_ci{ 7798c2ecf20Sopenharmony_ci struct go7007 *go = 7808c2ecf20Sopenharmony_ci container_of(ctrl->handler, struct go7007, hdl); 7818c2ecf20Sopenharmony_ci unsigned y; 7828c2ecf20Sopenharmony_ci u8 *mt; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci switch (ctrl->id) { 7858c2ecf20Sopenharmony_ci case V4L2_CID_PIXEL_THRESHOLD0: 7868c2ecf20Sopenharmony_ci go->modet[0].pixel_threshold = ctrl->val; 7878c2ecf20Sopenharmony_ci break; 7888c2ecf20Sopenharmony_ci case V4L2_CID_MOTION_THRESHOLD0: 7898c2ecf20Sopenharmony_ci go->modet[0].motion_threshold = ctrl->val; 7908c2ecf20Sopenharmony_ci break; 7918c2ecf20Sopenharmony_ci case V4L2_CID_MB_THRESHOLD0: 7928c2ecf20Sopenharmony_ci go->modet[0].mb_threshold = ctrl->val; 7938c2ecf20Sopenharmony_ci break; 7948c2ecf20Sopenharmony_ci case V4L2_CID_PIXEL_THRESHOLD1: 7958c2ecf20Sopenharmony_ci go->modet[1].pixel_threshold = ctrl->val; 7968c2ecf20Sopenharmony_ci break; 7978c2ecf20Sopenharmony_ci case V4L2_CID_MOTION_THRESHOLD1: 7988c2ecf20Sopenharmony_ci go->modet[1].motion_threshold = ctrl->val; 7998c2ecf20Sopenharmony_ci break; 8008c2ecf20Sopenharmony_ci case V4L2_CID_MB_THRESHOLD1: 8018c2ecf20Sopenharmony_ci go->modet[1].mb_threshold = ctrl->val; 8028c2ecf20Sopenharmony_ci break; 8038c2ecf20Sopenharmony_ci case V4L2_CID_PIXEL_THRESHOLD2: 8048c2ecf20Sopenharmony_ci go->modet[2].pixel_threshold = ctrl->val; 8058c2ecf20Sopenharmony_ci break; 8068c2ecf20Sopenharmony_ci case V4L2_CID_MOTION_THRESHOLD2: 8078c2ecf20Sopenharmony_ci go->modet[2].motion_threshold = ctrl->val; 8088c2ecf20Sopenharmony_ci break; 8098c2ecf20Sopenharmony_ci case V4L2_CID_MB_THRESHOLD2: 8108c2ecf20Sopenharmony_ci go->modet[2].mb_threshold = ctrl->val; 8118c2ecf20Sopenharmony_ci break; 8128c2ecf20Sopenharmony_ci case V4L2_CID_PIXEL_THRESHOLD3: 8138c2ecf20Sopenharmony_ci go->modet[3].pixel_threshold = ctrl->val; 8148c2ecf20Sopenharmony_ci break; 8158c2ecf20Sopenharmony_ci case V4L2_CID_MOTION_THRESHOLD3: 8168c2ecf20Sopenharmony_ci go->modet[3].motion_threshold = ctrl->val; 8178c2ecf20Sopenharmony_ci break; 8188c2ecf20Sopenharmony_ci case V4L2_CID_MB_THRESHOLD3: 8198c2ecf20Sopenharmony_ci go->modet[3].mb_threshold = ctrl->val; 8208c2ecf20Sopenharmony_ci break; 8218c2ecf20Sopenharmony_ci case V4L2_CID_DETECT_MD_REGION_GRID: 8228c2ecf20Sopenharmony_ci mt = go->modet_map; 8238c2ecf20Sopenharmony_ci for (y = 0; y < go->height / 16; y++, mt += go->width / 16) 8248c2ecf20Sopenharmony_ci memcpy(mt, ctrl->p_new.p_u8 + y * (720 / 16), go->width / 16); 8258c2ecf20Sopenharmony_ci break; 8268c2ecf20Sopenharmony_ci default: 8278c2ecf20Sopenharmony_ci return -EINVAL; 8288c2ecf20Sopenharmony_ci } 8298c2ecf20Sopenharmony_ci return 0; 8308c2ecf20Sopenharmony_ci} 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_cistatic const struct v4l2_file_operations go7007_fops = { 8338c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 8348c2ecf20Sopenharmony_ci .open = v4l2_fh_open, 8358c2ecf20Sopenharmony_ci .release = vb2_fop_release, 8368c2ecf20Sopenharmony_ci .unlocked_ioctl = video_ioctl2, 8378c2ecf20Sopenharmony_ci .read = vb2_fop_read, 8388c2ecf20Sopenharmony_ci .mmap = vb2_fop_mmap, 8398c2ecf20Sopenharmony_ci .poll = vb2_fop_poll, 8408c2ecf20Sopenharmony_ci}; 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_cistatic const struct v4l2_ioctl_ops video_ioctl_ops = { 8438c2ecf20Sopenharmony_ci .vidioc_querycap = vidioc_querycap, 8448c2ecf20Sopenharmony_ci .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, 8458c2ecf20Sopenharmony_ci .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, 8468c2ecf20Sopenharmony_ci .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, 8478c2ecf20Sopenharmony_ci .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, 8488c2ecf20Sopenharmony_ci .vidioc_reqbufs = vb2_ioctl_reqbufs, 8498c2ecf20Sopenharmony_ci .vidioc_querybuf = vb2_ioctl_querybuf, 8508c2ecf20Sopenharmony_ci .vidioc_qbuf = vb2_ioctl_qbuf, 8518c2ecf20Sopenharmony_ci .vidioc_dqbuf = vb2_ioctl_dqbuf, 8528c2ecf20Sopenharmony_ci .vidioc_g_std = vidioc_g_std, 8538c2ecf20Sopenharmony_ci .vidioc_s_std = vidioc_s_std, 8548c2ecf20Sopenharmony_ci .vidioc_querystd = vidioc_querystd, 8558c2ecf20Sopenharmony_ci .vidioc_enum_input = vidioc_enum_input, 8568c2ecf20Sopenharmony_ci .vidioc_g_input = vidioc_g_input, 8578c2ecf20Sopenharmony_ci .vidioc_s_input = vidioc_s_input, 8588c2ecf20Sopenharmony_ci .vidioc_enumaudio = vidioc_enumaudio, 8598c2ecf20Sopenharmony_ci .vidioc_g_audio = vidioc_g_audio, 8608c2ecf20Sopenharmony_ci .vidioc_s_audio = vidioc_s_audio, 8618c2ecf20Sopenharmony_ci .vidioc_streamon = vb2_ioctl_streamon, 8628c2ecf20Sopenharmony_ci .vidioc_streamoff = vb2_ioctl_streamoff, 8638c2ecf20Sopenharmony_ci .vidioc_g_tuner = vidioc_g_tuner, 8648c2ecf20Sopenharmony_ci .vidioc_s_tuner = vidioc_s_tuner, 8658c2ecf20Sopenharmony_ci .vidioc_g_frequency = vidioc_g_frequency, 8668c2ecf20Sopenharmony_ci .vidioc_s_frequency = vidioc_s_frequency, 8678c2ecf20Sopenharmony_ci .vidioc_g_parm = vidioc_g_parm, 8688c2ecf20Sopenharmony_ci .vidioc_s_parm = vidioc_s_parm, 8698c2ecf20Sopenharmony_ci .vidioc_enum_framesizes = vidioc_enum_framesizes, 8708c2ecf20Sopenharmony_ci .vidioc_enum_frameintervals = vidioc_enum_frameintervals, 8718c2ecf20Sopenharmony_ci .vidioc_log_status = vidioc_log_status, 8728c2ecf20Sopenharmony_ci .vidioc_subscribe_event = vidioc_subscribe_event, 8738c2ecf20Sopenharmony_ci .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 8748c2ecf20Sopenharmony_ci}; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_cistatic const struct video_device go7007_template = { 8778c2ecf20Sopenharmony_ci .name = "go7007", 8788c2ecf20Sopenharmony_ci .fops = &go7007_fops, 8798c2ecf20Sopenharmony_ci .release = video_device_release_empty, 8808c2ecf20Sopenharmony_ci .ioctl_ops = &video_ioctl_ops, 8818c2ecf20Sopenharmony_ci .tvnorms = V4L2_STD_ALL, 8828c2ecf20Sopenharmony_ci}; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_ops go7007_ctrl_ops = { 8858c2ecf20Sopenharmony_ci .s_ctrl = go7007_s_ctrl, 8868c2ecf20Sopenharmony_ci}; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_config go7007_pixel_threshold0_ctrl = { 8898c2ecf20Sopenharmony_ci .ops = &go7007_ctrl_ops, 8908c2ecf20Sopenharmony_ci .id = V4L2_CID_PIXEL_THRESHOLD0, 8918c2ecf20Sopenharmony_ci .name = "Pixel Threshold Region 0", 8928c2ecf20Sopenharmony_ci .type = V4L2_CTRL_TYPE_INTEGER, 8938c2ecf20Sopenharmony_ci .def = 20, 8948c2ecf20Sopenharmony_ci .max = 32767, 8958c2ecf20Sopenharmony_ci .step = 1, 8968c2ecf20Sopenharmony_ci}; 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_config go7007_motion_threshold0_ctrl = { 8998c2ecf20Sopenharmony_ci .ops = &go7007_ctrl_ops, 9008c2ecf20Sopenharmony_ci .id = V4L2_CID_MOTION_THRESHOLD0, 9018c2ecf20Sopenharmony_ci .name = "Motion Threshold Region 0", 9028c2ecf20Sopenharmony_ci .type = V4L2_CTRL_TYPE_INTEGER, 9038c2ecf20Sopenharmony_ci .def = 80, 9048c2ecf20Sopenharmony_ci .max = 32767, 9058c2ecf20Sopenharmony_ci .step = 1, 9068c2ecf20Sopenharmony_ci}; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_config go7007_mb_threshold0_ctrl = { 9098c2ecf20Sopenharmony_ci .ops = &go7007_ctrl_ops, 9108c2ecf20Sopenharmony_ci .id = V4L2_CID_MB_THRESHOLD0, 9118c2ecf20Sopenharmony_ci .name = "MB Threshold Region 0", 9128c2ecf20Sopenharmony_ci .type = V4L2_CTRL_TYPE_INTEGER, 9138c2ecf20Sopenharmony_ci .def = 200, 9148c2ecf20Sopenharmony_ci .max = 32767, 9158c2ecf20Sopenharmony_ci .step = 1, 9168c2ecf20Sopenharmony_ci}; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_config go7007_pixel_threshold1_ctrl = { 9198c2ecf20Sopenharmony_ci .ops = &go7007_ctrl_ops, 9208c2ecf20Sopenharmony_ci .id = V4L2_CID_PIXEL_THRESHOLD1, 9218c2ecf20Sopenharmony_ci .name = "Pixel Threshold Region 1", 9228c2ecf20Sopenharmony_ci .type = V4L2_CTRL_TYPE_INTEGER, 9238c2ecf20Sopenharmony_ci .def = 20, 9248c2ecf20Sopenharmony_ci .max = 32767, 9258c2ecf20Sopenharmony_ci .step = 1, 9268c2ecf20Sopenharmony_ci}; 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_config go7007_motion_threshold1_ctrl = { 9298c2ecf20Sopenharmony_ci .ops = &go7007_ctrl_ops, 9308c2ecf20Sopenharmony_ci .id = V4L2_CID_MOTION_THRESHOLD1, 9318c2ecf20Sopenharmony_ci .name = "Motion Threshold Region 1", 9328c2ecf20Sopenharmony_ci .type = V4L2_CTRL_TYPE_INTEGER, 9338c2ecf20Sopenharmony_ci .def = 80, 9348c2ecf20Sopenharmony_ci .max = 32767, 9358c2ecf20Sopenharmony_ci .step = 1, 9368c2ecf20Sopenharmony_ci}; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_config go7007_mb_threshold1_ctrl = { 9398c2ecf20Sopenharmony_ci .ops = &go7007_ctrl_ops, 9408c2ecf20Sopenharmony_ci .id = V4L2_CID_MB_THRESHOLD1, 9418c2ecf20Sopenharmony_ci .name = "MB Threshold Region 1", 9428c2ecf20Sopenharmony_ci .type = V4L2_CTRL_TYPE_INTEGER, 9438c2ecf20Sopenharmony_ci .def = 200, 9448c2ecf20Sopenharmony_ci .max = 32767, 9458c2ecf20Sopenharmony_ci .step = 1, 9468c2ecf20Sopenharmony_ci}; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_config go7007_pixel_threshold2_ctrl = { 9498c2ecf20Sopenharmony_ci .ops = &go7007_ctrl_ops, 9508c2ecf20Sopenharmony_ci .id = V4L2_CID_PIXEL_THRESHOLD2, 9518c2ecf20Sopenharmony_ci .name = "Pixel Threshold Region 2", 9528c2ecf20Sopenharmony_ci .type = V4L2_CTRL_TYPE_INTEGER, 9538c2ecf20Sopenharmony_ci .def = 20, 9548c2ecf20Sopenharmony_ci .max = 32767, 9558c2ecf20Sopenharmony_ci .step = 1, 9568c2ecf20Sopenharmony_ci}; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_config go7007_motion_threshold2_ctrl = { 9598c2ecf20Sopenharmony_ci .ops = &go7007_ctrl_ops, 9608c2ecf20Sopenharmony_ci .id = V4L2_CID_MOTION_THRESHOLD2, 9618c2ecf20Sopenharmony_ci .name = "Motion Threshold Region 2", 9628c2ecf20Sopenharmony_ci .type = V4L2_CTRL_TYPE_INTEGER, 9638c2ecf20Sopenharmony_ci .def = 80, 9648c2ecf20Sopenharmony_ci .max = 32767, 9658c2ecf20Sopenharmony_ci .step = 1, 9668c2ecf20Sopenharmony_ci}; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_config go7007_mb_threshold2_ctrl = { 9698c2ecf20Sopenharmony_ci .ops = &go7007_ctrl_ops, 9708c2ecf20Sopenharmony_ci .id = V4L2_CID_MB_THRESHOLD2, 9718c2ecf20Sopenharmony_ci .name = "MB Threshold Region 2", 9728c2ecf20Sopenharmony_ci .type = V4L2_CTRL_TYPE_INTEGER, 9738c2ecf20Sopenharmony_ci .def = 200, 9748c2ecf20Sopenharmony_ci .max = 32767, 9758c2ecf20Sopenharmony_ci .step = 1, 9768c2ecf20Sopenharmony_ci}; 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_config go7007_pixel_threshold3_ctrl = { 9798c2ecf20Sopenharmony_ci .ops = &go7007_ctrl_ops, 9808c2ecf20Sopenharmony_ci .id = V4L2_CID_PIXEL_THRESHOLD3, 9818c2ecf20Sopenharmony_ci .name = "Pixel Threshold Region 3", 9828c2ecf20Sopenharmony_ci .type = V4L2_CTRL_TYPE_INTEGER, 9838c2ecf20Sopenharmony_ci .def = 20, 9848c2ecf20Sopenharmony_ci .max = 32767, 9858c2ecf20Sopenharmony_ci .step = 1, 9868c2ecf20Sopenharmony_ci}; 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_config go7007_motion_threshold3_ctrl = { 9898c2ecf20Sopenharmony_ci .ops = &go7007_ctrl_ops, 9908c2ecf20Sopenharmony_ci .id = V4L2_CID_MOTION_THRESHOLD3, 9918c2ecf20Sopenharmony_ci .name = "Motion Threshold Region 3", 9928c2ecf20Sopenharmony_ci .type = V4L2_CTRL_TYPE_INTEGER, 9938c2ecf20Sopenharmony_ci .def = 80, 9948c2ecf20Sopenharmony_ci .max = 32767, 9958c2ecf20Sopenharmony_ci .step = 1, 9968c2ecf20Sopenharmony_ci}; 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_config go7007_mb_threshold3_ctrl = { 9998c2ecf20Sopenharmony_ci .ops = &go7007_ctrl_ops, 10008c2ecf20Sopenharmony_ci .id = V4L2_CID_MB_THRESHOLD3, 10018c2ecf20Sopenharmony_ci .name = "MB Threshold Region 3", 10028c2ecf20Sopenharmony_ci .type = V4L2_CTRL_TYPE_INTEGER, 10038c2ecf20Sopenharmony_ci .def = 200, 10048c2ecf20Sopenharmony_ci .max = 32767, 10058c2ecf20Sopenharmony_ci .step = 1, 10068c2ecf20Sopenharmony_ci}; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_config go7007_mb_regions_ctrl = { 10098c2ecf20Sopenharmony_ci .ops = &go7007_ctrl_ops, 10108c2ecf20Sopenharmony_ci .id = V4L2_CID_DETECT_MD_REGION_GRID, 10118c2ecf20Sopenharmony_ci .dims = { 576 / 16, 720 / 16 }, 10128c2ecf20Sopenharmony_ci .max = 3, 10138c2ecf20Sopenharmony_ci .step = 1, 10148c2ecf20Sopenharmony_ci}; 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ciint go7007_v4l2_ctrl_init(struct go7007 *go) 10178c2ecf20Sopenharmony_ci{ 10188c2ecf20Sopenharmony_ci struct v4l2_ctrl_handler *hdl = &go->hdl; 10198c2ecf20Sopenharmony_ci struct v4l2_ctrl *ctrl; 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci v4l2_ctrl_handler_init(hdl, 22); 10228c2ecf20Sopenharmony_ci go->mpeg_video_gop_size = v4l2_ctrl_new_std(hdl, NULL, 10238c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_GOP_SIZE, 0, 34, 1, 15); 10248c2ecf20Sopenharmony_ci go->mpeg_video_gop_closure = v4l2_ctrl_new_std(hdl, NULL, 10258c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, 0, 1, 1, 1); 10268c2ecf20Sopenharmony_ci go->mpeg_video_bitrate = v4l2_ctrl_new_std(hdl, NULL, 10278c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_BITRATE, 10288c2ecf20Sopenharmony_ci 64000, 10000000, 1, 9800000); 10298c2ecf20Sopenharmony_ci go->mpeg_video_b_frames = v4l2_ctrl_new_std(hdl, NULL, 10308c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_B_FRAMES, 0, 2, 2, 0); 10318c2ecf20Sopenharmony_ci go->mpeg_video_rep_seqheader = v4l2_ctrl_new_std(hdl, NULL, 10328c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER, 0, 1, 1, 1); 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci go->mpeg_video_aspect_ratio = v4l2_ctrl_new_std_menu(hdl, NULL, 10358c2ecf20Sopenharmony_ci V4L2_CID_MPEG_VIDEO_ASPECT, 10368c2ecf20Sopenharmony_ci V4L2_MPEG_VIDEO_ASPECT_16x9, 0, 10378c2ecf20Sopenharmony_ci V4L2_MPEG_VIDEO_ASPECT_1x1); 10388c2ecf20Sopenharmony_ci ctrl = v4l2_ctrl_new_std(hdl, NULL, 10398c2ecf20Sopenharmony_ci V4L2_CID_JPEG_ACTIVE_MARKER, 0, 10408c2ecf20Sopenharmony_ci V4L2_JPEG_ACTIVE_MARKER_DQT | 10418c2ecf20Sopenharmony_ci V4L2_JPEG_ACTIVE_MARKER_DHT, 0, 10428c2ecf20Sopenharmony_ci V4L2_JPEG_ACTIVE_MARKER_DQT | 10438c2ecf20Sopenharmony_ci V4L2_JPEG_ACTIVE_MARKER_DHT); 10448c2ecf20Sopenharmony_ci if (ctrl) 10458c2ecf20Sopenharmony_ci ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; 10468c2ecf20Sopenharmony_ci v4l2_ctrl_new_custom(hdl, &go7007_pixel_threshold0_ctrl, NULL); 10478c2ecf20Sopenharmony_ci v4l2_ctrl_new_custom(hdl, &go7007_motion_threshold0_ctrl, NULL); 10488c2ecf20Sopenharmony_ci v4l2_ctrl_new_custom(hdl, &go7007_mb_threshold0_ctrl, NULL); 10498c2ecf20Sopenharmony_ci v4l2_ctrl_new_custom(hdl, &go7007_pixel_threshold1_ctrl, NULL); 10508c2ecf20Sopenharmony_ci v4l2_ctrl_new_custom(hdl, &go7007_motion_threshold1_ctrl, NULL); 10518c2ecf20Sopenharmony_ci v4l2_ctrl_new_custom(hdl, &go7007_mb_threshold1_ctrl, NULL); 10528c2ecf20Sopenharmony_ci v4l2_ctrl_new_custom(hdl, &go7007_pixel_threshold2_ctrl, NULL); 10538c2ecf20Sopenharmony_ci v4l2_ctrl_new_custom(hdl, &go7007_motion_threshold2_ctrl, NULL); 10548c2ecf20Sopenharmony_ci v4l2_ctrl_new_custom(hdl, &go7007_mb_threshold2_ctrl, NULL); 10558c2ecf20Sopenharmony_ci v4l2_ctrl_new_custom(hdl, &go7007_pixel_threshold3_ctrl, NULL); 10568c2ecf20Sopenharmony_ci v4l2_ctrl_new_custom(hdl, &go7007_motion_threshold3_ctrl, NULL); 10578c2ecf20Sopenharmony_ci v4l2_ctrl_new_custom(hdl, &go7007_mb_threshold3_ctrl, NULL); 10588c2ecf20Sopenharmony_ci v4l2_ctrl_new_custom(hdl, &go7007_mb_regions_ctrl, NULL); 10598c2ecf20Sopenharmony_ci go->modet_mode = v4l2_ctrl_new_std_menu(hdl, NULL, 10608c2ecf20Sopenharmony_ci V4L2_CID_DETECT_MD_MODE, 10618c2ecf20Sopenharmony_ci V4L2_DETECT_MD_MODE_REGION_GRID, 10628c2ecf20Sopenharmony_ci 1 << V4L2_DETECT_MD_MODE_THRESHOLD_GRID, 10638c2ecf20Sopenharmony_ci V4L2_DETECT_MD_MODE_DISABLED); 10648c2ecf20Sopenharmony_ci if (hdl->error) { 10658c2ecf20Sopenharmony_ci int rv = hdl->error; 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci v4l2_err(&go->v4l2_dev, "Could not register controls\n"); 10688c2ecf20Sopenharmony_ci return rv; 10698c2ecf20Sopenharmony_ci } 10708c2ecf20Sopenharmony_ci go->v4l2_dev.ctrl_handler = hdl; 10718c2ecf20Sopenharmony_ci return 0; 10728c2ecf20Sopenharmony_ci} 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ciint go7007_v4l2_init(struct go7007 *go) 10758c2ecf20Sopenharmony_ci{ 10768c2ecf20Sopenharmony_ci struct video_device *vdev = &go->vdev; 10778c2ecf20Sopenharmony_ci int rv; 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci mutex_init(&go->serialize_lock); 10808c2ecf20Sopenharmony_ci mutex_init(&go->queue_lock); 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&go->vidq_active); 10838c2ecf20Sopenharmony_ci go->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 10848c2ecf20Sopenharmony_ci go->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; 10858c2ecf20Sopenharmony_ci go->vidq.ops = &go7007_video_qops; 10868c2ecf20Sopenharmony_ci go->vidq.mem_ops = &vb2_vmalloc_memops; 10878c2ecf20Sopenharmony_ci go->vidq.drv_priv = go; 10888c2ecf20Sopenharmony_ci go->vidq.buf_struct_size = sizeof(struct go7007_buffer); 10898c2ecf20Sopenharmony_ci go->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; 10908c2ecf20Sopenharmony_ci go->vidq.lock = &go->queue_lock; 10918c2ecf20Sopenharmony_ci rv = vb2_queue_init(&go->vidq); 10928c2ecf20Sopenharmony_ci if (rv) 10938c2ecf20Sopenharmony_ci return rv; 10948c2ecf20Sopenharmony_ci *vdev = go7007_template; 10958c2ecf20Sopenharmony_ci vdev->lock = &go->serialize_lock; 10968c2ecf20Sopenharmony_ci vdev->queue = &go->vidq; 10978c2ecf20Sopenharmony_ci vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | 10988c2ecf20Sopenharmony_ci V4L2_CAP_STREAMING; 10998c2ecf20Sopenharmony_ci if (go->board_info->num_aud_inputs) 11008c2ecf20Sopenharmony_ci vdev->device_caps |= V4L2_CAP_AUDIO; 11018c2ecf20Sopenharmony_ci if (go->board_info->flags & GO7007_BOARD_HAS_TUNER) 11028c2ecf20Sopenharmony_ci vdev->device_caps |= V4L2_CAP_TUNER; 11038c2ecf20Sopenharmony_ci video_set_drvdata(vdev, go); 11048c2ecf20Sopenharmony_ci vdev->v4l2_dev = &go->v4l2_dev; 11058c2ecf20Sopenharmony_ci if (!v4l2_device_has_op(&go->v4l2_dev, 0, video, querystd)) 11068c2ecf20Sopenharmony_ci v4l2_disable_ioctl(vdev, VIDIOC_QUERYSTD); 11078c2ecf20Sopenharmony_ci if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER)) { 11088c2ecf20Sopenharmony_ci v4l2_disable_ioctl(vdev, VIDIOC_S_FREQUENCY); 11098c2ecf20Sopenharmony_ci v4l2_disable_ioctl(vdev, VIDIOC_G_FREQUENCY); 11108c2ecf20Sopenharmony_ci v4l2_disable_ioctl(vdev, VIDIOC_S_TUNER); 11118c2ecf20Sopenharmony_ci v4l2_disable_ioctl(vdev, VIDIOC_G_TUNER); 11128c2ecf20Sopenharmony_ci } else { 11138c2ecf20Sopenharmony_ci struct v4l2_frequency f = { 11148c2ecf20Sopenharmony_ci .type = V4L2_TUNER_ANALOG_TV, 11158c2ecf20Sopenharmony_ci .frequency = 980, 11168c2ecf20Sopenharmony_ci }; 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci call_all(&go->v4l2_dev, tuner, s_frequency, &f); 11198c2ecf20Sopenharmony_ci } 11208c2ecf20Sopenharmony_ci if (!(go->board_info->sensor_flags & GO7007_SENSOR_TV)) { 11218c2ecf20Sopenharmony_ci v4l2_disable_ioctl(vdev, VIDIOC_G_STD); 11228c2ecf20Sopenharmony_ci v4l2_disable_ioctl(vdev, VIDIOC_S_STD); 11238c2ecf20Sopenharmony_ci vdev->tvnorms = 0; 11248c2ecf20Sopenharmony_ci } 11258c2ecf20Sopenharmony_ci if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING) 11268c2ecf20Sopenharmony_ci v4l2_disable_ioctl(vdev, VIDIOC_ENUM_FRAMESIZES); 11278c2ecf20Sopenharmony_ci if (go->board_info->num_aud_inputs == 0) { 11288c2ecf20Sopenharmony_ci v4l2_disable_ioctl(vdev, VIDIOC_G_AUDIO); 11298c2ecf20Sopenharmony_ci v4l2_disable_ioctl(vdev, VIDIOC_S_AUDIO); 11308c2ecf20Sopenharmony_ci v4l2_disable_ioctl(vdev, VIDIOC_ENUMAUDIO); 11318c2ecf20Sopenharmony_ci } 11328c2ecf20Sopenharmony_ci /* Setup correct crystal frequency on this board */ 11338c2ecf20Sopenharmony_ci if (go->board_info->sensor_flags & GO7007_SENSOR_SAA7115) 11348c2ecf20Sopenharmony_ci v4l2_subdev_call(go->sd_video, video, s_crystal_freq, 11358c2ecf20Sopenharmony_ci SAA7115_FREQ_24_576_MHZ, 11368c2ecf20Sopenharmony_ci SAA7115_FREQ_FL_APLL | SAA7115_FREQ_FL_UCGC | 11378c2ecf20Sopenharmony_ci SAA7115_FREQ_FL_DOUBLE_ASCLK); 11388c2ecf20Sopenharmony_ci go7007_s_input(go); 11398c2ecf20Sopenharmony_ci if (go->board_info->sensor_flags & GO7007_SENSOR_TV) 11408c2ecf20Sopenharmony_ci go7007_s_std(go); 11418c2ecf20Sopenharmony_ci rv = video_register_device(vdev, VFL_TYPE_VIDEO, -1); 11428c2ecf20Sopenharmony_ci if (rv < 0) 11438c2ecf20Sopenharmony_ci return rv; 11448c2ecf20Sopenharmony_ci dev_info(go->dev, "registered device %s [v4l2]\n", 11458c2ecf20Sopenharmony_ci video_device_node_name(vdev)); 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci return 0; 11488c2ecf20Sopenharmony_ci} 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_civoid go7007_v4l2_remove(struct go7007 *go) 11518c2ecf20Sopenharmony_ci{ 11528c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(&go->hdl); 11538c2ecf20Sopenharmony_ci} 1154