11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 27955f03dSHans Verkuil /* 37955f03dSHans Verkuil * Copyright (C) 2005-2006 Micronas USA Inc. 47955f03dSHans Verkuil */ 57955f03dSHans Verkuil 67955f03dSHans Verkuil #include <linux/module.h> 77955f03dSHans Verkuil #include <linux/delay.h> 87955f03dSHans Verkuil #include <linux/sched.h> 97955f03dSHans Verkuil #include <linux/spinlock.h> 107955f03dSHans Verkuil #include <linux/slab.h> 117955f03dSHans Verkuil #include <linux/fs.h> 127955f03dSHans Verkuil #include <linux/unistd.h> 137955f03dSHans Verkuil #include <linux/time.h> 147955f03dSHans Verkuil #include <linux/vmalloc.h> 157955f03dSHans Verkuil #include <linux/pagemap.h> 167955f03dSHans Verkuil #include <linux/i2c.h> 177955f03dSHans Verkuil #include <linux/mutex.h> 187955f03dSHans Verkuil #include <linux/uaccess.h> 197955f03dSHans Verkuil #include <linux/videodev2.h> 207955f03dSHans Verkuil #include <media/v4l2-common.h> 217955f03dSHans Verkuil #include <media/v4l2-ioctl.h> 227955f03dSHans Verkuil #include <media/v4l2-subdev.h> 237955f03dSHans Verkuil #include <media/v4l2-event.h> 247955f03dSHans Verkuil #include <media/videobuf2-vmalloc.h> 25b5dcee22SMauro Carvalho Chehab #include <media/i2c/saa7115.h> 267955f03dSHans Verkuil 277955f03dSHans Verkuil #include "go7007-priv.h" 287955f03dSHans Verkuil 297955f03dSHans Verkuil #define call_all(dev, o, f, args...) \ 307955f03dSHans Verkuil v4l2_device_call_until_err(dev, 0, o, f, ##args) 317955f03dSHans Verkuil 327955f03dSHans Verkuil static bool valid_pixelformat(u32 pixelformat) 337955f03dSHans Verkuil { 347955f03dSHans Verkuil switch (pixelformat) { 357955f03dSHans Verkuil case V4L2_PIX_FMT_MJPEG: 367955f03dSHans Verkuil case V4L2_PIX_FMT_MPEG1: 377955f03dSHans Verkuil case V4L2_PIX_FMT_MPEG2: 387955f03dSHans Verkuil case V4L2_PIX_FMT_MPEG4: 397955f03dSHans Verkuil return true; 407955f03dSHans Verkuil default: 417955f03dSHans Verkuil return false; 427955f03dSHans Verkuil } 437955f03dSHans Verkuil } 447955f03dSHans Verkuil 457955f03dSHans Verkuil static u32 get_frame_type_flag(struct go7007_buffer *vb, int format) 467955f03dSHans Verkuil { 472d700715SJunghak Sung u8 *ptr = vb2_plane_vaddr(&vb->vb.vb2_buf, 0); 487955f03dSHans Verkuil 497955f03dSHans Verkuil switch (format) { 507955f03dSHans Verkuil case V4L2_PIX_FMT_MJPEG: 517955f03dSHans Verkuil return V4L2_BUF_FLAG_KEYFRAME; 527955f03dSHans Verkuil case V4L2_PIX_FMT_MPEG4: 537955f03dSHans Verkuil switch ((ptr[vb->frame_offset + 4] >> 6) & 0x3) { 547955f03dSHans Verkuil case 0: 557955f03dSHans Verkuil return V4L2_BUF_FLAG_KEYFRAME; 567955f03dSHans Verkuil case 1: 577955f03dSHans Verkuil return V4L2_BUF_FLAG_PFRAME; 587955f03dSHans Verkuil case 2: 597955f03dSHans Verkuil return V4L2_BUF_FLAG_BFRAME; 607955f03dSHans Verkuil default: 617955f03dSHans Verkuil return 0; 627955f03dSHans Verkuil } 637955f03dSHans Verkuil case V4L2_PIX_FMT_MPEG1: 647955f03dSHans Verkuil case V4L2_PIX_FMT_MPEG2: 657955f03dSHans Verkuil switch ((ptr[vb->frame_offset + 5] >> 3) & 0x7) { 667955f03dSHans Verkuil case 1: 677955f03dSHans Verkuil return V4L2_BUF_FLAG_KEYFRAME; 687955f03dSHans Verkuil case 2: 697955f03dSHans Verkuil return V4L2_BUF_FLAG_PFRAME; 707955f03dSHans Verkuil case 3: 717955f03dSHans Verkuil return V4L2_BUF_FLAG_BFRAME; 727955f03dSHans Verkuil default: 737955f03dSHans Verkuil return 0; 747955f03dSHans Verkuil } 757955f03dSHans Verkuil } 767955f03dSHans Verkuil 777955f03dSHans Verkuil return 0; 787955f03dSHans Verkuil } 797955f03dSHans Verkuil 807955f03dSHans Verkuil static void get_resolution(struct go7007 *go, int *width, int *height) 817955f03dSHans Verkuil { 827955f03dSHans Verkuil switch (go->standard) { 837955f03dSHans Verkuil case GO7007_STD_NTSC: 847955f03dSHans Verkuil *width = 720; 857955f03dSHans Verkuil *height = 480; 867955f03dSHans Verkuil break; 877955f03dSHans Verkuil case GO7007_STD_PAL: 887955f03dSHans Verkuil *width = 720; 897955f03dSHans Verkuil *height = 576; 907955f03dSHans Verkuil break; 917955f03dSHans Verkuil case GO7007_STD_OTHER: 927955f03dSHans Verkuil default: 937955f03dSHans Verkuil *width = go->board_info->sensor_width; 947955f03dSHans Verkuil *height = go->board_info->sensor_height; 957955f03dSHans Verkuil break; 967955f03dSHans Verkuil } 977955f03dSHans Verkuil } 987955f03dSHans Verkuil 997955f03dSHans Verkuil static void set_formatting(struct go7007 *go) 1007955f03dSHans Verkuil { 1017955f03dSHans Verkuil if (go->format == V4L2_PIX_FMT_MJPEG) { 1027955f03dSHans Verkuil go->pali = 0; 1037955f03dSHans Verkuil go->aspect_ratio = GO7007_RATIO_1_1; 1047955f03dSHans Verkuil go->gop_size = 0; 1057955f03dSHans Verkuil go->ipb = 0; 1067955f03dSHans Verkuil go->closed_gop = 0; 1077955f03dSHans Verkuil go->repeat_seqhead = 0; 1087955f03dSHans Verkuil go->seq_header_enable = 0; 1097955f03dSHans Verkuil go->gop_header_enable = 0; 1107955f03dSHans Verkuil go->dvd_mode = 0; 1117955f03dSHans Verkuil return; 1127955f03dSHans Verkuil } 1137955f03dSHans Verkuil 1147955f03dSHans Verkuil switch (go->format) { 1157955f03dSHans Verkuil case V4L2_PIX_FMT_MPEG1: 1167955f03dSHans Verkuil go->pali = 0; 1177955f03dSHans Verkuil break; 1187955f03dSHans Verkuil default: 1197955f03dSHans Verkuil case V4L2_PIX_FMT_MPEG2: 1207955f03dSHans Verkuil go->pali = 0x48; 1217955f03dSHans Verkuil break; 1227955f03dSHans Verkuil case V4L2_PIX_FMT_MPEG4: 1237955f03dSHans Verkuil /* For future reference: this is the list of MPEG4 1247955f03dSHans Verkuil * profiles that are available, although they are 1257955f03dSHans Verkuil * untested: 1267955f03dSHans Verkuil * 1277955f03dSHans Verkuil * Profile pali 1287955f03dSHans Verkuil * -------------- ---- 1297955f03dSHans Verkuil * PROFILE_S_L0 0x08 1307955f03dSHans Verkuil * PROFILE_S_L1 0x01 1317955f03dSHans Verkuil * PROFILE_S_L2 0x02 1327955f03dSHans Verkuil * PROFILE_S_L3 0x03 1337955f03dSHans Verkuil * PROFILE_ARTS_L1 0x91 1347955f03dSHans Verkuil * PROFILE_ARTS_L2 0x92 1357955f03dSHans Verkuil * PROFILE_ARTS_L3 0x93 1367955f03dSHans Verkuil * PROFILE_ARTS_L4 0x94 1377955f03dSHans Verkuil * PROFILE_AS_L0 0xf0 1387955f03dSHans Verkuil * PROFILE_AS_L1 0xf1 1397955f03dSHans Verkuil * PROFILE_AS_L2 0xf2 1407955f03dSHans Verkuil * PROFILE_AS_L3 0xf3 1417955f03dSHans Verkuil * PROFILE_AS_L4 0xf4 1427955f03dSHans Verkuil * PROFILE_AS_L5 0xf5 1437955f03dSHans Verkuil */ 1447955f03dSHans Verkuil go->pali = 0xf5; 1457955f03dSHans Verkuil break; 1467955f03dSHans Verkuil } 1477955f03dSHans Verkuil go->gop_size = v4l2_ctrl_g_ctrl(go->mpeg_video_gop_size); 1487955f03dSHans Verkuil go->closed_gop = v4l2_ctrl_g_ctrl(go->mpeg_video_gop_closure); 1497955f03dSHans Verkuil go->ipb = v4l2_ctrl_g_ctrl(go->mpeg_video_b_frames) != 0; 1507955f03dSHans Verkuil go->bitrate = v4l2_ctrl_g_ctrl(go->mpeg_video_bitrate); 1517955f03dSHans Verkuil go->repeat_seqhead = v4l2_ctrl_g_ctrl(go->mpeg_video_rep_seqheader); 1527955f03dSHans Verkuil go->gop_header_enable = 1; 1537955f03dSHans Verkuil go->dvd_mode = 0; 1547955f03dSHans Verkuil if (go->format == V4L2_PIX_FMT_MPEG2) 1557955f03dSHans Verkuil go->dvd_mode = 1567955f03dSHans Verkuil go->bitrate == 9800000 && 1577955f03dSHans Verkuil go->gop_size == 15 && 1587955f03dSHans Verkuil go->ipb == 0 && 1597955f03dSHans Verkuil go->repeat_seqhead == 1 && 1607955f03dSHans Verkuil go->closed_gop; 1617955f03dSHans Verkuil 1627955f03dSHans Verkuil switch (v4l2_ctrl_g_ctrl(go->mpeg_video_aspect_ratio)) { 1637955f03dSHans Verkuil default: 1647955f03dSHans Verkuil case V4L2_MPEG_VIDEO_ASPECT_1x1: 1657955f03dSHans Verkuil go->aspect_ratio = GO7007_RATIO_1_1; 1667955f03dSHans Verkuil break; 1677955f03dSHans Verkuil case V4L2_MPEG_VIDEO_ASPECT_4x3: 1687955f03dSHans Verkuil go->aspect_ratio = GO7007_RATIO_4_3; 1697955f03dSHans Verkuil break; 1707955f03dSHans Verkuil case V4L2_MPEG_VIDEO_ASPECT_16x9: 1717955f03dSHans Verkuil go->aspect_ratio = GO7007_RATIO_16_9; 1727955f03dSHans Verkuil break; 1737955f03dSHans Verkuil } 1747955f03dSHans Verkuil } 1757955f03dSHans Verkuil 1767955f03dSHans Verkuil static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try) 1777955f03dSHans Verkuil { 1787955f03dSHans Verkuil int sensor_height = 0, sensor_width = 0; 1797955f03dSHans Verkuil int width, height; 1807955f03dSHans Verkuil 1817955f03dSHans Verkuil if (fmt != NULL && !valid_pixelformat(fmt->fmt.pix.pixelformat)) 1827955f03dSHans Verkuil return -EINVAL; 1837955f03dSHans Verkuil 1847955f03dSHans Verkuil get_resolution(go, &sensor_width, &sensor_height); 1857955f03dSHans Verkuil 1867955f03dSHans Verkuil if (fmt == NULL) { 1877955f03dSHans Verkuil width = sensor_width; 1887955f03dSHans Verkuil height = sensor_height; 1897955f03dSHans Verkuil } else if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING) { 1907955f03dSHans Verkuil if (fmt->fmt.pix.width > sensor_width) 1917955f03dSHans Verkuil width = sensor_width; 1927955f03dSHans Verkuil else if (fmt->fmt.pix.width < 144) 1937955f03dSHans Verkuil width = 144; 1947955f03dSHans Verkuil else 1957955f03dSHans Verkuil width = fmt->fmt.pix.width & ~0x0f; 1967955f03dSHans Verkuil 1977955f03dSHans Verkuil if (fmt->fmt.pix.height > sensor_height) 1987955f03dSHans Verkuil height = sensor_height; 1997955f03dSHans Verkuil else if (fmt->fmt.pix.height < 96) 2007955f03dSHans Verkuil height = 96; 2017955f03dSHans Verkuil else 2027955f03dSHans Verkuil height = fmt->fmt.pix.height & ~0x0f; 2037955f03dSHans Verkuil } else { 2047955f03dSHans Verkuil width = fmt->fmt.pix.width; 2057955f03dSHans Verkuil 2067955f03dSHans Verkuil if (width <= sensor_width / 4) { 2077955f03dSHans Verkuil width = sensor_width / 4; 2087955f03dSHans Verkuil height = sensor_height / 4; 2097955f03dSHans Verkuil } else if (width <= sensor_width / 2) { 2107955f03dSHans Verkuil width = sensor_width / 2; 2117955f03dSHans Verkuil height = sensor_height / 2; 2127955f03dSHans Verkuil } else { 2137955f03dSHans Verkuil width = sensor_width; 2147955f03dSHans Verkuil height = sensor_height; 2157955f03dSHans Verkuil } 2167955f03dSHans Verkuil width &= ~0xf; 2177955f03dSHans Verkuil height &= ~0xf; 2187955f03dSHans Verkuil } 2197955f03dSHans Verkuil 2207955f03dSHans Verkuil if (fmt != NULL) { 2217955f03dSHans Verkuil u32 pixelformat = fmt->fmt.pix.pixelformat; 2227955f03dSHans Verkuil 2237955f03dSHans Verkuil memset(fmt, 0, sizeof(*fmt)); 2247955f03dSHans Verkuil fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 2257955f03dSHans Verkuil fmt->fmt.pix.width = width; 2267955f03dSHans Verkuil fmt->fmt.pix.height = height; 2277955f03dSHans Verkuil fmt->fmt.pix.pixelformat = pixelformat; 2287955f03dSHans Verkuil fmt->fmt.pix.field = V4L2_FIELD_NONE; 2297955f03dSHans Verkuil fmt->fmt.pix.bytesperline = 0; 2307955f03dSHans Verkuil fmt->fmt.pix.sizeimage = GO7007_BUF_SIZE; 2317955f03dSHans Verkuil fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; 2327955f03dSHans Verkuil } 2337955f03dSHans Verkuil 2347955f03dSHans Verkuil if (try) 2357955f03dSHans Verkuil return 0; 2367955f03dSHans Verkuil 2377955f03dSHans Verkuil if (fmt) 2387955f03dSHans Verkuil go->format = fmt->fmt.pix.pixelformat; 2397955f03dSHans Verkuil go->width = width; 2407955f03dSHans Verkuil go->height = height; 2417955f03dSHans Verkuil go->encoder_h_offset = go->board_info->sensor_h_offset; 2427955f03dSHans Verkuil go->encoder_v_offset = go->board_info->sensor_v_offset; 2437955f03dSHans Verkuil 2447955f03dSHans Verkuil if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING) { 245ebf984bbSHans Verkuil struct v4l2_subdev_format format = { 246ebf984bbSHans Verkuil .which = V4L2_SUBDEV_FORMAT_ACTIVE, 247ebf984bbSHans Verkuil }; 2487955f03dSHans Verkuil 249ebf984bbSHans Verkuil format.format.code = MEDIA_BUS_FMT_FIXED; 250ebf984bbSHans Verkuil format.format.width = fmt ? fmt->fmt.pix.width : width; 251ebf984bbSHans Verkuil format.format.height = height; 2527955f03dSHans Verkuil go->encoder_h_halve = 0; 2537955f03dSHans Verkuil go->encoder_v_halve = 0; 2547955f03dSHans Verkuil go->encoder_subsample = 0; 255ebf984bbSHans Verkuil call_all(&go->v4l2_dev, pad, set_fmt, NULL, &format); 2567955f03dSHans Verkuil } else { 2577955f03dSHans Verkuil if (width <= sensor_width / 4) { 2587955f03dSHans Verkuil go->encoder_h_halve = 1; 2597955f03dSHans Verkuil go->encoder_v_halve = 1; 2607955f03dSHans Verkuil go->encoder_subsample = 1; 2617955f03dSHans Verkuil } else if (width <= sensor_width / 2) { 2627955f03dSHans Verkuil go->encoder_h_halve = 1; 2637955f03dSHans Verkuil go->encoder_v_halve = 1; 2647955f03dSHans Verkuil go->encoder_subsample = 0; 2657955f03dSHans Verkuil } else { 2667955f03dSHans Verkuil go->encoder_h_halve = 0; 2677955f03dSHans Verkuil go->encoder_v_halve = 0; 2687955f03dSHans Verkuil go->encoder_subsample = 0; 2697955f03dSHans Verkuil } 2707955f03dSHans Verkuil } 2717955f03dSHans Verkuil return 0; 2727955f03dSHans Verkuil } 2737955f03dSHans Verkuil 2747955f03dSHans Verkuil static int vidioc_querycap(struct file *file, void *priv, 2757955f03dSHans Verkuil struct v4l2_capability *cap) 2767955f03dSHans Verkuil { 2777955f03dSHans Verkuil struct go7007 *go = video_drvdata(file); 2787955f03dSHans Verkuil 279c0decac1SMauro Carvalho Chehab strscpy(cap->driver, "go7007", sizeof(cap->driver)); 280c0decac1SMauro Carvalho Chehab strscpy(cap->card, go->name, sizeof(cap->card)); 281c0decac1SMauro Carvalho Chehab strscpy(cap->bus_info, go->bus_info, sizeof(cap->bus_info)); 2827955f03dSHans Verkuil 2837955f03dSHans Verkuil cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | 2847955f03dSHans Verkuil V4L2_CAP_STREAMING; 2857955f03dSHans Verkuil 2867955f03dSHans Verkuil if (go->board_info->num_aud_inputs) 2877955f03dSHans Verkuil cap->device_caps |= V4L2_CAP_AUDIO; 2887955f03dSHans Verkuil if (go->board_info->flags & GO7007_BOARD_HAS_TUNER) 2897955f03dSHans Verkuil cap->device_caps |= V4L2_CAP_TUNER; 2907955f03dSHans Verkuil cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; 2917955f03dSHans Verkuil return 0; 2927955f03dSHans Verkuil } 2937955f03dSHans Verkuil 2947955f03dSHans Verkuil static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, 2957955f03dSHans Verkuil struct v4l2_fmtdesc *fmt) 2967955f03dSHans Verkuil { 2977955f03dSHans Verkuil char *desc = NULL; 2987955f03dSHans Verkuil 2997955f03dSHans Verkuil switch (fmt->index) { 3007955f03dSHans Verkuil case 0: 3017955f03dSHans Verkuil fmt->pixelformat = V4L2_PIX_FMT_MJPEG; 3027955f03dSHans Verkuil desc = "Motion JPEG"; 3037955f03dSHans Verkuil break; 3047955f03dSHans Verkuil case 1: 3057955f03dSHans Verkuil fmt->pixelformat = V4L2_PIX_FMT_MPEG1; 3067955f03dSHans Verkuil desc = "MPEG-1 ES"; 3077955f03dSHans Verkuil break; 3087955f03dSHans Verkuil case 2: 3097955f03dSHans Verkuil fmt->pixelformat = V4L2_PIX_FMT_MPEG2; 3107955f03dSHans Verkuil desc = "MPEG-2 ES"; 3117955f03dSHans Verkuil break; 3127955f03dSHans Verkuil case 3: 3137955f03dSHans Verkuil fmt->pixelformat = V4L2_PIX_FMT_MPEG4; 3147955f03dSHans Verkuil desc = "MPEG-4 ES"; 3157955f03dSHans Verkuil break; 3167955f03dSHans Verkuil default: 3177955f03dSHans Verkuil return -EINVAL; 3187955f03dSHans Verkuil } 3197955f03dSHans Verkuil fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 3207955f03dSHans Verkuil fmt->flags = V4L2_FMT_FLAG_COMPRESSED; 3217955f03dSHans Verkuil 32285709cbfSMauro Carvalho Chehab strscpy(fmt->description, desc, sizeof(fmt->description)); 3237955f03dSHans Verkuil 3247955f03dSHans Verkuil return 0; 3257955f03dSHans Verkuil } 3267955f03dSHans Verkuil 3277955f03dSHans Verkuil static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, 3287955f03dSHans Verkuil struct v4l2_format *fmt) 3297955f03dSHans Verkuil { 3307955f03dSHans Verkuil struct go7007 *go = video_drvdata(file); 3317955f03dSHans Verkuil 3327955f03dSHans Verkuil fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 3337955f03dSHans Verkuil fmt->fmt.pix.width = go->width; 3347955f03dSHans Verkuil fmt->fmt.pix.height = go->height; 3357955f03dSHans Verkuil fmt->fmt.pix.pixelformat = go->format; 3367955f03dSHans Verkuil fmt->fmt.pix.field = V4L2_FIELD_NONE; 3377955f03dSHans Verkuil fmt->fmt.pix.bytesperline = 0; 3387955f03dSHans Verkuil fmt->fmt.pix.sizeimage = GO7007_BUF_SIZE; 3397955f03dSHans Verkuil fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; 3407955f03dSHans Verkuil 3417955f03dSHans Verkuil return 0; 3427955f03dSHans Verkuil } 3437955f03dSHans Verkuil 3447955f03dSHans Verkuil static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, 3457955f03dSHans Verkuil struct v4l2_format *fmt) 3467955f03dSHans Verkuil { 3477955f03dSHans Verkuil struct go7007 *go = video_drvdata(file); 3487955f03dSHans Verkuil 3497955f03dSHans Verkuil return set_capture_size(go, fmt, 1); 3507955f03dSHans Verkuil } 3517955f03dSHans Verkuil 3527955f03dSHans Verkuil static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, 3537955f03dSHans Verkuil struct v4l2_format *fmt) 3547955f03dSHans Verkuil { 3557955f03dSHans Verkuil struct go7007 *go = video_drvdata(file); 3567955f03dSHans Verkuil 3577955f03dSHans Verkuil if (vb2_is_busy(&go->vidq)) 3587955f03dSHans Verkuil return -EBUSY; 3597955f03dSHans Verkuil 3607955f03dSHans Verkuil return set_capture_size(go, fmt, 0); 3617955f03dSHans Verkuil } 3627955f03dSHans Verkuil 3637955f03dSHans Verkuil static int go7007_queue_setup(struct vb2_queue *q, 3647955f03dSHans Verkuil unsigned int *num_buffers, unsigned int *num_planes, 36536c0f8b3SHans Verkuil unsigned int sizes[], struct device *alloc_devs[]) 3667955f03dSHans Verkuil { 3677955f03dSHans Verkuil sizes[0] = GO7007_BUF_SIZE; 3687955f03dSHans Verkuil *num_planes = 1; 3697955f03dSHans Verkuil 3707955f03dSHans Verkuil if (*num_buffers < 2) 3717955f03dSHans Verkuil *num_buffers = 2; 3727955f03dSHans Verkuil 3737955f03dSHans Verkuil return 0; 3747955f03dSHans Verkuil } 3757955f03dSHans Verkuil 3767955f03dSHans Verkuil static void go7007_buf_queue(struct vb2_buffer *vb) 3777955f03dSHans Verkuil { 3787955f03dSHans Verkuil struct vb2_queue *vq = vb->vb2_queue; 3797955f03dSHans Verkuil struct go7007 *go = vb2_get_drv_priv(vq); 3802d700715SJunghak Sung struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 3817955f03dSHans Verkuil struct go7007_buffer *go7007_vb = 3822d700715SJunghak Sung container_of(vbuf, struct go7007_buffer, vb); 3837955f03dSHans Verkuil unsigned long flags; 3847955f03dSHans Verkuil 3857955f03dSHans Verkuil spin_lock_irqsave(&go->spinlock, flags); 3867955f03dSHans Verkuil list_add_tail(&go7007_vb->list, &go->vidq_active); 3877955f03dSHans Verkuil spin_unlock_irqrestore(&go->spinlock, flags); 3887955f03dSHans Verkuil } 3897955f03dSHans Verkuil 3907955f03dSHans Verkuil static int go7007_buf_prepare(struct vb2_buffer *vb) 3917955f03dSHans Verkuil { 3922d700715SJunghak Sung struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 3937955f03dSHans Verkuil struct go7007_buffer *go7007_vb = 3942d700715SJunghak Sung container_of(vbuf, struct go7007_buffer, vb); 3957955f03dSHans Verkuil 3967955f03dSHans Verkuil go7007_vb->modet_active = 0; 3977955f03dSHans Verkuil go7007_vb->frame_offset = 0; 3982d700715SJunghak Sung vb->planes[0].bytesused = 0; 3997955f03dSHans Verkuil return 0; 4007955f03dSHans Verkuil } 4017955f03dSHans Verkuil 4027955f03dSHans Verkuil static void go7007_buf_finish(struct vb2_buffer *vb) 4037955f03dSHans Verkuil { 4047955f03dSHans Verkuil struct vb2_queue *vq = vb->vb2_queue; 4057955f03dSHans Verkuil struct go7007 *go = vb2_get_drv_priv(vq); 4062d700715SJunghak Sung struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 4077955f03dSHans Verkuil struct go7007_buffer *go7007_vb = 4082d700715SJunghak Sung container_of(vbuf, struct go7007_buffer, vb); 4097955f03dSHans Verkuil u32 frame_type_flag = get_frame_type_flag(go7007_vb, go->format); 4107955f03dSHans Verkuil 4112d700715SJunghak Sung vbuf->flags &= ~(V4L2_BUF_FLAG_KEYFRAME | V4L2_BUF_FLAG_BFRAME | 4127955f03dSHans Verkuil V4L2_BUF_FLAG_PFRAME); 4132d700715SJunghak Sung vbuf->flags |= frame_type_flag; 4142d700715SJunghak Sung vbuf->field = V4L2_FIELD_NONE; 4157955f03dSHans Verkuil } 4167955f03dSHans Verkuil 4177955f03dSHans Verkuil static int go7007_start_streaming(struct vb2_queue *q, unsigned int count) 4187955f03dSHans Verkuil { 4197955f03dSHans Verkuil struct go7007 *go = vb2_get_drv_priv(q); 4207955f03dSHans Verkuil int ret; 4217955f03dSHans Verkuil 4227955f03dSHans Verkuil set_formatting(go); 4237955f03dSHans Verkuil mutex_lock(&go->hw_lock); 4247955f03dSHans Verkuil go->next_seq = 0; 4257955f03dSHans Verkuil go->active_buf = NULL; 4267955f03dSHans Verkuil go->modet_event_status = 0; 4277955f03dSHans Verkuil q->streaming = 1; 4287955f03dSHans Verkuil if (go7007_start_encoder(go) < 0) 4297955f03dSHans Verkuil ret = -EIO; 4307955f03dSHans Verkuil else 4317955f03dSHans Verkuil ret = 0; 4327955f03dSHans Verkuil mutex_unlock(&go->hw_lock); 4337955f03dSHans Verkuil if (ret) { 4347955f03dSHans Verkuil q->streaming = 0; 4357955f03dSHans Verkuil return ret; 4367955f03dSHans Verkuil } 4377955f03dSHans Verkuil call_all(&go->v4l2_dev, video, s_stream, 1); 4387955f03dSHans Verkuil v4l2_ctrl_grab(go->mpeg_video_gop_size, true); 4397955f03dSHans Verkuil v4l2_ctrl_grab(go->mpeg_video_gop_closure, true); 4407955f03dSHans Verkuil v4l2_ctrl_grab(go->mpeg_video_bitrate, true); 4417955f03dSHans Verkuil v4l2_ctrl_grab(go->mpeg_video_aspect_ratio, true); 4427955f03dSHans Verkuil /* Turn on Capture LED */ 4437955f03dSHans Verkuil if (go->board_id == GO7007_BOARDID_ADS_USBAV_709) 4447955f03dSHans Verkuil go7007_write_addr(go, 0x3c82, 0x0005); 4457955f03dSHans Verkuil return ret; 4467955f03dSHans Verkuil } 4477955f03dSHans Verkuil 4487955f03dSHans Verkuil static void go7007_stop_streaming(struct vb2_queue *q) 4497955f03dSHans Verkuil { 4507955f03dSHans Verkuil struct go7007 *go = vb2_get_drv_priv(q); 4517955f03dSHans Verkuil unsigned long flags; 4527955f03dSHans Verkuil 4537955f03dSHans Verkuil q->streaming = 0; 4547955f03dSHans Verkuil go7007_stream_stop(go); 4557955f03dSHans Verkuil mutex_lock(&go->hw_lock); 4567955f03dSHans Verkuil go7007_reset_encoder(go); 4577955f03dSHans Verkuil mutex_unlock(&go->hw_lock); 4587955f03dSHans Verkuil call_all(&go->v4l2_dev, video, s_stream, 0); 4597955f03dSHans Verkuil 4607955f03dSHans Verkuil spin_lock_irqsave(&go->spinlock, flags); 4617955f03dSHans Verkuil INIT_LIST_HEAD(&go->vidq_active); 4627955f03dSHans Verkuil spin_unlock_irqrestore(&go->spinlock, flags); 4637955f03dSHans Verkuil v4l2_ctrl_grab(go->mpeg_video_gop_size, false); 4647955f03dSHans Verkuil v4l2_ctrl_grab(go->mpeg_video_gop_closure, false); 4657955f03dSHans Verkuil v4l2_ctrl_grab(go->mpeg_video_bitrate, false); 4667955f03dSHans Verkuil v4l2_ctrl_grab(go->mpeg_video_aspect_ratio, false); 4677955f03dSHans Verkuil /* Turn on Capture LED */ 4687955f03dSHans Verkuil if (go->board_id == GO7007_BOARDID_ADS_USBAV_709) 4697955f03dSHans Verkuil go7007_write_addr(go, 0x3c82, 0x000d); 4707955f03dSHans Verkuil } 4717955f03dSHans Verkuil 4721bc17717SJulia Lawall static const struct vb2_ops go7007_video_qops = { 4737955f03dSHans Verkuil .queue_setup = go7007_queue_setup, 4747955f03dSHans Verkuil .buf_queue = go7007_buf_queue, 4757955f03dSHans Verkuil .buf_prepare = go7007_buf_prepare, 4767955f03dSHans Verkuil .buf_finish = go7007_buf_finish, 4777955f03dSHans Verkuil .start_streaming = go7007_start_streaming, 4787955f03dSHans Verkuil .stop_streaming = go7007_stop_streaming, 4797955f03dSHans Verkuil .wait_prepare = vb2_ops_wait_prepare, 4807955f03dSHans Verkuil .wait_finish = vb2_ops_wait_finish, 4817955f03dSHans Verkuil }; 4827955f03dSHans Verkuil 4837955f03dSHans Verkuil static int vidioc_g_parm(struct file *filp, void *priv, 4847955f03dSHans Verkuil struct v4l2_streamparm *parm) 4857955f03dSHans Verkuil { 4867955f03dSHans Verkuil struct go7007 *go = video_drvdata(filp); 4877955f03dSHans Verkuil struct v4l2_fract timeperframe = { 4887955f03dSHans Verkuil .numerator = 1001 * go->fps_scale, 4897955f03dSHans Verkuil .denominator = go->sensor_framerate, 4907955f03dSHans Verkuil }; 4917955f03dSHans Verkuil 4927955f03dSHans Verkuil if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 4937955f03dSHans Verkuil return -EINVAL; 4947955f03dSHans Verkuil 4957955f03dSHans Verkuil parm->parm.capture.readbuffers = 2; 4967955f03dSHans Verkuil parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; 4977955f03dSHans Verkuil parm->parm.capture.timeperframe = timeperframe; 4987955f03dSHans Verkuil 4997955f03dSHans Verkuil return 0; 5007955f03dSHans Verkuil } 5017955f03dSHans Verkuil 5027955f03dSHans Verkuil static int vidioc_s_parm(struct file *filp, void *priv, 5037955f03dSHans Verkuil struct v4l2_streamparm *parm) 5047955f03dSHans Verkuil { 5057955f03dSHans Verkuil struct go7007 *go = video_drvdata(filp); 5067955f03dSHans Verkuil unsigned int n, d; 5077955f03dSHans Verkuil 5087955f03dSHans Verkuil if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 5097955f03dSHans Verkuil return -EINVAL; 5107955f03dSHans Verkuil 5117955f03dSHans Verkuil n = go->sensor_framerate * 5127955f03dSHans Verkuil parm->parm.capture.timeperframe.numerator; 5137955f03dSHans Verkuil d = 1001 * parm->parm.capture.timeperframe.denominator; 5147955f03dSHans Verkuil if (n != 0 && d != 0 && n > d) 5157955f03dSHans Verkuil go->fps_scale = (n + d/2) / d; 5167955f03dSHans Verkuil else 5177955f03dSHans Verkuil go->fps_scale = 1; 5187955f03dSHans Verkuil 5197955f03dSHans Verkuil return vidioc_g_parm(filp, priv, parm); 5207955f03dSHans Verkuil } 5217955f03dSHans Verkuil 5227955f03dSHans Verkuil /* VIDIOC_ENUMSTD on go7007 were used for enumerating the supported fps and 5237955f03dSHans Verkuil its resolution, when the device is not connected to TV. 5247955f03dSHans Verkuil This is were an API abuse, probably used by the lack of specific IOCTL's to 5257955f03dSHans Verkuil enumerate it, by the time the driver was written. 5267955f03dSHans Verkuil 5277955f03dSHans Verkuil However, since kernel 2.6.19, two new ioctls (VIDIOC_ENUM_FRAMEINTERVALS 5287955f03dSHans Verkuil and VIDIOC_ENUM_FRAMESIZES) were added for this purpose. 5297955f03dSHans Verkuil 5307955f03dSHans Verkuil The two functions below implement the newer ioctls 5317955f03dSHans Verkuil */ 5327955f03dSHans Verkuil static int vidioc_enum_framesizes(struct file *filp, void *priv, 5337955f03dSHans Verkuil struct v4l2_frmsizeenum *fsize) 5347955f03dSHans Verkuil { 5357955f03dSHans Verkuil struct go7007 *go = video_drvdata(filp); 5367955f03dSHans Verkuil int width, height; 5377955f03dSHans Verkuil 5387955f03dSHans Verkuil if (fsize->index > 2) 5397955f03dSHans Verkuil return -EINVAL; 5407955f03dSHans Verkuil 5417955f03dSHans Verkuil if (!valid_pixelformat(fsize->pixel_format)) 5427955f03dSHans Verkuil return -EINVAL; 5437955f03dSHans Verkuil 5447955f03dSHans Verkuil get_resolution(go, &width, &height); 5457955f03dSHans Verkuil fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; 5467955f03dSHans Verkuil fsize->discrete.width = (width >> fsize->index) & ~0xf; 5477955f03dSHans Verkuil fsize->discrete.height = (height >> fsize->index) & ~0xf; 5487955f03dSHans Verkuil return 0; 5497955f03dSHans Verkuil } 5507955f03dSHans Verkuil 5517955f03dSHans Verkuil static int vidioc_enum_frameintervals(struct file *filp, void *priv, 5527955f03dSHans Verkuil struct v4l2_frmivalenum *fival) 5537955f03dSHans Verkuil { 5547955f03dSHans Verkuil struct go7007 *go = video_drvdata(filp); 5557955f03dSHans Verkuil int width, height; 5567955f03dSHans Verkuil int i; 5577955f03dSHans Verkuil 5587955f03dSHans Verkuil if (fival->index > 4) 5597955f03dSHans Verkuil return -EINVAL; 5607955f03dSHans Verkuil 5617955f03dSHans Verkuil if (!valid_pixelformat(fival->pixel_format)) 5627955f03dSHans Verkuil return -EINVAL; 5637955f03dSHans Verkuil 5647955f03dSHans Verkuil if (!(go->board_info->sensor_flags & GO7007_SENSOR_SCALING)) { 5657955f03dSHans Verkuil get_resolution(go, &width, &height); 5667955f03dSHans Verkuil for (i = 0; i <= 2; i++) 5677955f03dSHans Verkuil if (fival->width == ((width >> i) & ~0xf) && 5687955f03dSHans Verkuil fival->height == ((height >> i) & ~0xf)) 5697955f03dSHans Verkuil break; 5707955f03dSHans Verkuil if (i > 2) 5717955f03dSHans Verkuil return -EINVAL; 5727955f03dSHans Verkuil } 5737955f03dSHans Verkuil fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; 5747955f03dSHans Verkuil fival->discrete.numerator = 1001 * (fival->index + 1); 5757955f03dSHans Verkuil fival->discrete.denominator = go->sensor_framerate; 5767955f03dSHans Verkuil return 0; 5777955f03dSHans Verkuil } 5787955f03dSHans Verkuil 5797955f03dSHans Verkuil static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std) 5807955f03dSHans Verkuil { 5817955f03dSHans Verkuil struct go7007 *go = video_drvdata(file); 5827955f03dSHans Verkuil 5837955f03dSHans Verkuil *std = go->std; 5847955f03dSHans Verkuil return 0; 5857955f03dSHans Verkuil } 5867955f03dSHans Verkuil 5877955f03dSHans Verkuil static int go7007_s_std(struct go7007 *go) 5887955f03dSHans Verkuil { 5897955f03dSHans Verkuil if (go->std & V4L2_STD_625_50) { 5907955f03dSHans Verkuil go->standard = GO7007_STD_PAL; 5917955f03dSHans Verkuil go->sensor_framerate = 25025; 5927955f03dSHans Verkuil } else { 5937955f03dSHans Verkuil go->standard = GO7007_STD_NTSC; 5947955f03dSHans Verkuil go->sensor_framerate = 30000; 5957955f03dSHans Verkuil } 5967955f03dSHans Verkuil 5977955f03dSHans Verkuil call_all(&go->v4l2_dev, video, s_std, go->std); 5987955f03dSHans Verkuil set_capture_size(go, NULL, 0); 5997955f03dSHans Verkuil return 0; 6007955f03dSHans Verkuil } 6017955f03dSHans Verkuil 6027955f03dSHans Verkuil static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id std) 6037955f03dSHans Verkuil { 6047955f03dSHans Verkuil struct go7007 *go = video_drvdata(file); 6057955f03dSHans Verkuil 6067955f03dSHans Verkuil if (vb2_is_busy(&go->vidq)) 6077955f03dSHans Verkuil return -EBUSY; 6087955f03dSHans Verkuil 6097955f03dSHans Verkuil go->std = std; 6107955f03dSHans Verkuil 6117955f03dSHans Verkuil return go7007_s_std(go); 6127955f03dSHans Verkuil } 6137955f03dSHans Verkuil 6147955f03dSHans Verkuil static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *std) 6157955f03dSHans Verkuil { 6167955f03dSHans Verkuil struct go7007 *go = video_drvdata(file); 6177955f03dSHans Verkuil 6187955f03dSHans Verkuil return call_all(&go->v4l2_dev, video, querystd, std); 6197955f03dSHans Verkuil } 6207955f03dSHans Verkuil 6217955f03dSHans Verkuil static int vidioc_enum_input(struct file *file, void *priv, 6227955f03dSHans Verkuil struct v4l2_input *inp) 6237955f03dSHans Verkuil { 6247955f03dSHans Verkuil struct go7007 *go = video_drvdata(file); 6257955f03dSHans Verkuil 6267955f03dSHans Verkuil if (inp->index >= go->board_info->num_inputs) 6277955f03dSHans Verkuil return -EINVAL; 6287955f03dSHans Verkuil 629c0decac1SMauro Carvalho Chehab strscpy(inp->name, go->board_info->inputs[inp->index].name, 6307955f03dSHans Verkuil sizeof(inp->name)); 6317955f03dSHans Verkuil 6327955f03dSHans Verkuil /* If this board has a tuner, it will be the first input */ 6337955f03dSHans Verkuil if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) && 6347955f03dSHans Verkuil inp->index == 0) 6357955f03dSHans Verkuil inp->type = V4L2_INPUT_TYPE_TUNER; 6367955f03dSHans Verkuil else 6377955f03dSHans Verkuil inp->type = V4L2_INPUT_TYPE_CAMERA; 6387955f03dSHans Verkuil 6397955f03dSHans Verkuil if (go->board_info->num_aud_inputs) 6407955f03dSHans Verkuil inp->audioset = (1 << go->board_info->num_aud_inputs) - 1; 6417955f03dSHans Verkuil else 6427955f03dSHans Verkuil inp->audioset = 0; 6437955f03dSHans Verkuil inp->tuner = 0; 6447955f03dSHans Verkuil if (go->board_info->sensor_flags & GO7007_SENSOR_TV) 6457955f03dSHans Verkuil inp->std = video_devdata(file)->tvnorms; 6467955f03dSHans Verkuil else 6477955f03dSHans Verkuil inp->std = 0; 6487955f03dSHans Verkuil 6497955f03dSHans Verkuil return 0; 6507955f03dSHans Verkuil } 6517955f03dSHans Verkuil 6527955f03dSHans Verkuil 6537955f03dSHans Verkuil static int vidioc_g_input(struct file *file, void *priv, unsigned int *input) 6547955f03dSHans Verkuil { 6557955f03dSHans Verkuil struct go7007 *go = video_drvdata(file); 6567955f03dSHans Verkuil 6577955f03dSHans Verkuil *input = go->input; 6587955f03dSHans Verkuil 6597955f03dSHans Verkuil return 0; 6607955f03dSHans Verkuil } 6617955f03dSHans Verkuil 6627955f03dSHans Verkuil static int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *a) 6637955f03dSHans Verkuil { 6647955f03dSHans Verkuil struct go7007 *go = video_drvdata(file); 6657955f03dSHans Verkuil 6667955f03dSHans Verkuil if (a->index >= go->board_info->num_aud_inputs) 6677955f03dSHans Verkuil return -EINVAL; 668c0decac1SMauro Carvalho Chehab strscpy(a->name, go->board_info->aud_inputs[a->index].name, 6697955f03dSHans Verkuil sizeof(a->name)); 6707955f03dSHans Verkuil a->capability = V4L2_AUDCAP_STEREO; 6717955f03dSHans Verkuil return 0; 6727955f03dSHans Verkuil } 6737955f03dSHans Verkuil 6747955f03dSHans Verkuil static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a) 6757955f03dSHans Verkuil { 6767955f03dSHans Verkuil struct go7007 *go = video_drvdata(file); 6777955f03dSHans Verkuil 6787955f03dSHans Verkuil a->index = go->aud_input; 679c0decac1SMauro Carvalho Chehab strscpy(a->name, go->board_info->aud_inputs[go->aud_input].name, 6807955f03dSHans Verkuil sizeof(a->name)); 6817955f03dSHans Verkuil a->capability = V4L2_AUDCAP_STEREO; 6827955f03dSHans Verkuil return 0; 6837955f03dSHans Verkuil } 6847955f03dSHans Verkuil 6857955f03dSHans Verkuil static int vidioc_s_audio(struct file *file, void *fh, 6867955f03dSHans Verkuil const struct v4l2_audio *a) 6877955f03dSHans Verkuil { 6887955f03dSHans Verkuil struct go7007 *go = video_drvdata(file); 6897955f03dSHans Verkuil 6907955f03dSHans Verkuil if (a->index >= go->board_info->num_aud_inputs) 6917955f03dSHans Verkuil return -EINVAL; 6927955f03dSHans Verkuil go->aud_input = a->index; 6937955f03dSHans Verkuil v4l2_subdev_call(go->sd_audio, audio, s_routing, 6947955f03dSHans Verkuil go->board_info->aud_inputs[go->aud_input].audio_input, 0, 0); 6957955f03dSHans Verkuil return 0; 6967955f03dSHans Verkuil } 6977955f03dSHans Verkuil 6987955f03dSHans Verkuil static void go7007_s_input(struct go7007 *go) 6997955f03dSHans Verkuil { 7007955f03dSHans Verkuil unsigned int input = go->input; 7017955f03dSHans Verkuil 7027955f03dSHans Verkuil v4l2_subdev_call(go->sd_video, video, s_routing, 7037955f03dSHans Verkuil go->board_info->inputs[input].video_input, 0, 7047955f03dSHans Verkuil go->board_info->video_config); 7057955f03dSHans Verkuil if (go->board_info->num_aud_inputs) { 7067955f03dSHans Verkuil int aud_input = go->board_info->inputs[input].audio_index; 7077955f03dSHans Verkuil 7087955f03dSHans Verkuil v4l2_subdev_call(go->sd_audio, audio, s_routing, 7097955f03dSHans Verkuil go->board_info->aud_inputs[aud_input].audio_input, 0, 0); 7107955f03dSHans Verkuil go->aud_input = aud_input; 7117955f03dSHans Verkuil } 7127955f03dSHans Verkuil } 7137955f03dSHans Verkuil 7147955f03dSHans Verkuil static int vidioc_s_input(struct file *file, void *priv, unsigned int input) 7157955f03dSHans Verkuil { 7167955f03dSHans Verkuil struct go7007 *go = video_drvdata(file); 7177955f03dSHans Verkuil 7187955f03dSHans Verkuil if (input >= go->board_info->num_inputs) 7197955f03dSHans Verkuil return -EINVAL; 7207955f03dSHans Verkuil if (vb2_is_busy(&go->vidq)) 7217955f03dSHans Verkuil return -EBUSY; 7227955f03dSHans Verkuil 7237955f03dSHans Verkuil go->input = input; 7247955f03dSHans Verkuil go7007_s_input(go); 7257955f03dSHans Verkuil 7267955f03dSHans Verkuil return 0; 7277955f03dSHans Verkuil } 7287955f03dSHans Verkuil 7297955f03dSHans Verkuil static int vidioc_g_tuner(struct file *file, void *priv, 7307955f03dSHans Verkuil struct v4l2_tuner *t) 7317955f03dSHans Verkuil { 7327955f03dSHans Verkuil struct go7007 *go = video_drvdata(file); 7337955f03dSHans Verkuil 7347955f03dSHans Verkuil if (t->index != 0) 7357955f03dSHans Verkuil return -EINVAL; 7367955f03dSHans Verkuil 737c0decac1SMauro Carvalho Chehab strscpy(t->name, "Tuner", sizeof(t->name)); 7387955f03dSHans Verkuil return call_all(&go->v4l2_dev, tuner, g_tuner, t); 7397955f03dSHans Verkuil } 7407955f03dSHans Verkuil 7417955f03dSHans Verkuil static int vidioc_s_tuner(struct file *file, void *priv, 7427955f03dSHans Verkuil const struct v4l2_tuner *t) 7437955f03dSHans Verkuil { 7447955f03dSHans Verkuil struct go7007 *go = video_drvdata(file); 7457955f03dSHans Verkuil 7467955f03dSHans Verkuil if (t->index != 0) 7477955f03dSHans Verkuil return -EINVAL; 7487955f03dSHans Verkuil 7497955f03dSHans Verkuil return call_all(&go->v4l2_dev, tuner, s_tuner, t); 7507955f03dSHans Verkuil } 7517955f03dSHans Verkuil 7527955f03dSHans Verkuil static int vidioc_g_frequency(struct file *file, void *priv, 7537955f03dSHans Verkuil struct v4l2_frequency *f) 7547955f03dSHans Verkuil { 7557955f03dSHans Verkuil struct go7007 *go = video_drvdata(file); 7567955f03dSHans Verkuil 7577955f03dSHans Verkuil if (f->tuner) 7587955f03dSHans Verkuil return -EINVAL; 7597955f03dSHans Verkuil 7607955f03dSHans Verkuil return call_all(&go->v4l2_dev, tuner, g_frequency, f); 7617955f03dSHans Verkuil } 7627955f03dSHans Verkuil 7637955f03dSHans Verkuil static int vidioc_s_frequency(struct file *file, void *priv, 7647955f03dSHans Verkuil const struct v4l2_frequency *f) 7657955f03dSHans Verkuil { 7667955f03dSHans Verkuil struct go7007 *go = video_drvdata(file); 7677955f03dSHans Verkuil 7687955f03dSHans Verkuil if (f->tuner) 7697955f03dSHans Verkuil return -EINVAL; 7707955f03dSHans Verkuil 7717955f03dSHans Verkuil return call_all(&go->v4l2_dev, tuner, s_frequency, f); 7727955f03dSHans Verkuil } 7737955f03dSHans Verkuil 7747955f03dSHans Verkuil static int vidioc_log_status(struct file *file, void *priv) 7757955f03dSHans Verkuil { 7767955f03dSHans Verkuil struct go7007 *go = video_drvdata(file); 7777955f03dSHans Verkuil 7787955f03dSHans Verkuil v4l2_ctrl_log_status(file, priv); 7797955f03dSHans Verkuil return call_all(&go->v4l2_dev, core, log_status); 7807955f03dSHans Verkuil } 7817955f03dSHans Verkuil 7827955f03dSHans Verkuil static int vidioc_subscribe_event(struct v4l2_fh *fh, 7837955f03dSHans Verkuil const struct v4l2_event_subscription *sub) 7847955f03dSHans Verkuil { 7857955f03dSHans Verkuil 7867955f03dSHans Verkuil switch (sub->type) { 7877955f03dSHans Verkuil case V4L2_EVENT_MOTION_DET: 7887955f03dSHans Verkuil /* Allow for up to 30 events (1 second for NTSC) to be 7897955f03dSHans Verkuil * stored. */ 7907955f03dSHans Verkuil return v4l2_event_subscribe(fh, sub, 30, NULL); 791c3d173a3SGustavo Padovan default: 792c3d173a3SGustavo Padovan return v4l2_ctrl_subscribe_event(fh, sub); 7937955f03dSHans Verkuil } 7947955f03dSHans Verkuil } 7957955f03dSHans Verkuil 7967955f03dSHans Verkuil 7977955f03dSHans Verkuil static int go7007_s_ctrl(struct v4l2_ctrl *ctrl) 7987955f03dSHans Verkuil { 7997955f03dSHans Verkuil struct go7007 *go = 8007955f03dSHans Verkuil container_of(ctrl->handler, struct go7007, hdl); 8017955f03dSHans Verkuil unsigned y; 8027955f03dSHans Verkuil u8 *mt; 8037955f03dSHans Verkuil 8047955f03dSHans Verkuil switch (ctrl->id) { 8057955f03dSHans Verkuil case V4L2_CID_PIXEL_THRESHOLD0: 8067955f03dSHans Verkuil go->modet[0].pixel_threshold = ctrl->val; 8077955f03dSHans Verkuil break; 8087955f03dSHans Verkuil case V4L2_CID_MOTION_THRESHOLD0: 8097955f03dSHans Verkuil go->modet[0].motion_threshold = ctrl->val; 8107955f03dSHans Verkuil break; 8117955f03dSHans Verkuil case V4L2_CID_MB_THRESHOLD0: 8127955f03dSHans Verkuil go->modet[0].mb_threshold = ctrl->val; 8137955f03dSHans Verkuil break; 8147955f03dSHans Verkuil case V4L2_CID_PIXEL_THRESHOLD1: 8157955f03dSHans Verkuil go->modet[1].pixel_threshold = ctrl->val; 8167955f03dSHans Verkuil break; 8177955f03dSHans Verkuil case V4L2_CID_MOTION_THRESHOLD1: 8187955f03dSHans Verkuil go->modet[1].motion_threshold = ctrl->val; 8197955f03dSHans Verkuil break; 8207955f03dSHans Verkuil case V4L2_CID_MB_THRESHOLD1: 8217955f03dSHans Verkuil go->modet[1].mb_threshold = ctrl->val; 8227955f03dSHans Verkuil break; 8237955f03dSHans Verkuil case V4L2_CID_PIXEL_THRESHOLD2: 8247955f03dSHans Verkuil go->modet[2].pixel_threshold = ctrl->val; 8257955f03dSHans Verkuil break; 8267955f03dSHans Verkuil case V4L2_CID_MOTION_THRESHOLD2: 8277955f03dSHans Verkuil go->modet[2].motion_threshold = ctrl->val; 8287955f03dSHans Verkuil break; 8297955f03dSHans Verkuil case V4L2_CID_MB_THRESHOLD2: 8307955f03dSHans Verkuil go->modet[2].mb_threshold = ctrl->val; 8317955f03dSHans Verkuil break; 8327955f03dSHans Verkuil case V4L2_CID_PIXEL_THRESHOLD3: 8337955f03dSHans Verkuil go->modet[3].pixel_threshold = ctrl->val; 8347955f03dSHans Verkuil break; 8357955f03dSHans Verkuil case V4L2_CID_MOTION_THRESHOLD3: 8367955f03dSHans Verkuil go->modet[3].motion_threshold = ctrl->val; 8377955f03dSHans Verkuil break; 8387955f03dSHans Verkuil case V4L2_CID_MB_THRESHOLD3: 8397955f03dSHans Verkuil go->modet[3].mb_threshold = ctrl->val; 8407955f03dSHans Verkuil break; 8417955f03dSHans Verkuil case V4L2_CID_DETECT_MD_REGION_GRID: 8427955f03dSHans Verkuil mt = go->modet_map; 8437955f03dSHans Verkuil for (y = 0; y < go->height / 16; y++, mt += go->width / 16) 8447955f03dSHans Verkuil memcpy(mt, ctrl->p_new.p_u8 + y * (720 / 16), go->width / 16); 8457955f03dSHans Verkuil break; 8467955f03dSHans Verkuil default: 8477955f03dSHans Verkuil return -EINVAL; 8487955f03dSHans Verkuil } 8497955f03dSHans Verkuil return 0; 8507955f03dSHans Verkuil } 8517955f03dSHans Verkuil 852ff05c984SBhumika Goyal static const struct v4l2_file_operations go7007_fops = { 8537955f03dSHans Verkuil .owner = THIS_MODULE, 8547955f03dSHans Verkuil .open = v4l2_fh_open, 8557955f03dSHans Verkuil .release = vb2_fop_release, 8567955f03dSHans Verkuil .unlocked_ioctl = video_ioctl2, 8577955f03dSHans Verkuil .read = vb2_fop_read, 8587955f03dSHans Verkuil .mmap = vb2_fop_mmap, 8597955f03dSHans Verkuil .poll = vb2_fop_poll, 8607955f03dSHans Verkuil }; 8617955f03dSHans Verkuil 8627955f03dSHans Verkuil static const struct v4l2_ioctl_ops video_ioctl_ops = { 8637955f03dSHans Verkuil .vidioc_querycap = vidioc_querycap, 8647955f03dSHans Verkuil .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, 8657955f03dSHans Verkuil .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, 8667955f03dSHans Verkuil .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, 8677955f03dSHans Verkuil .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, 8687955f03dSHans Verkuil .vidioc_reqbufs = vb2_ioctl_reqbufs, 8697955f03dSHans Verkuil .vidioc_querybuf = vb2_ioctl_querybuf, 8707955f03dSHans Verkuil .vidioc_qbuf = vb2_ioctl_qbuf, 8717955f03dSHans Verkuil .vidioc_dqbuf = vb2_ioctl_dqbuf, 8727955f03dSHans Verkuil .vidioc_g_std = vidioc_g_std, 8737955f03dSHans Verkuil .vidioc_s_std = vidioc_s_std, 8747955f03dSHans Verkuil .vidioc_querystd = vidioc_querystd, 8757955f03dSHans Verkuil .vidioc_enum_input = vidioc_enum_input, 8767955f03dSHans Verkuil .vidioc_g_input = vidioc_g_input, 8777955f03dSHans Verkuil .vidioc_s_input = vidioc_s_input, 8787955f03dSHans Verkuil .vidioc_enumaudio = vidioc_enumaudio, 8797955f03dSHans Verkuil .vidioc_g_audio = vidioc_g_audio, 8807955f03dSHans Verkuil .vidioc_s_audio = vidioc_s_audio, 8817955f03dSHans Verkuil .vidioc_streamon = vb2_ioctl_streamon, 8827955f03dSHans Verkuil .vidioc_streamoff = vb2_ioctl_streamoff, 8837955f03dSHans Verkuil .vidioc_g_tuner = vidioc_g_tuner, 8847955f03dSHans Verkuil .vidioc_s_tuner = vidioc_s_tuner, 8857955f03dSHans Verkuil .vidioc_g_frequency = vidioc_g_frequency, 8867955f03dSHans Verkuil .vidioc_s_frequency = vidioc_s_frequency, 8877955f03dSHans Verkuil .vidioc_g_parm = vidioc_g_parm, 8887955f03dSHans Verkuil .vidioc_s_parm = vidioc_s_parm, 8897955f03dSHans Verkuil .vidioc_enum_framesizes = vidioc_enum_framesizes, 8907955f03dSHans Verkuil .vidioc_enum_frameintervals = vidioc_enum_frameintervals, 8917955f03dSHans Verkuil .vidioc_log_status = vidioc_log_status, 8927955f03dSHans Verkuil .vidioc_subscribe_event = vidioc_subscribe_event, 8937955f03dSHans Verkuil .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 8947955f03dSHans Verkuil }; 8957955f03dSHans Verkuil 89686844942SBhumika Goyal static const struct video_device go7007_template = { 8977955f03dSHans Verkuil .name = "go7007", 8987955f03dSHans Verkuil .fops = &go7007_fops, 8997955f03dSHans Verkuil .release = video_device_release_empty, 9007955f03dSHans Verkuil .ioctl_ops = &video_ioctl_ops, 9017955f03dSHans Verkuil .tvnorms = V4L2_STD_ALL, 9027955f03dSHans Verkuil }; 9037955f03dSHans Verkuil 9047955f03dSHans Verkuil static const struct v4l2_ctrl_ops go7007_ctrl_ops = { 9057955f03dSHans Verkuil .s_ctrl = go7007_s_ctrl, 9067955f03dSHans Verkuil }; 9077955f03dSHans Verkuil 9087955f03dSHans Verkuil static const struct v4l2_ctrl_config go7007_pixel_threshold0_ctrl = { 9097955f03dSHans Verkuil .ops = &go7007_ctrl_ops, 9107955f03dSHans Verkuil .id = V4L2_CID_PIXEL_THRESHOLD0, 9117955f03dSHans Verkuil .name = "Pixel Threshold Region 0", 9127955f03dSHans Verkuil .type = V4L2_CTRL_TYPE_INTEGER, 9137955f03dSHans Verkuil .def = 20, 9147955f03dSHans Verkuil .max = 32767, 9157955f03dSHans Verkuil .step = 1, 9167955f03dSHans Verkuil }; 9177955f03dSHans Verkuil 9187955f03dSHans Verkuil static const struct v4l2_ctrl_config go7007_motion_threshold0_ctrl = { 9197955f03dSHans Verkuil .ops = &go7007_ctrl_ops, 9207955f03dSHans Verkuil .id = V4L2_CID_MOTION_THRESHOLD0, 9217955f03dSHans Verkuil .name = "Motion Threshold Region 0", 9227955f03dSHans Verkuil .type = V4L2_CTRL_TYPE_INTEGER, 9237955f03dSHans Verkuil .def = 80, 9247955f03dSHans Verkuil .max = 32767, 9257955f03dSHans Verkuil .step = 1, 9267955f03dSHans Verkuil }; 9277955f03dSHans Verkuil 9287955f03dSHans Verkuil static const struct v4l2_ctrl_config go7007_mb_threshold0_ctrl = { 9297955f03dSHans Verkuil .ops = &go7007_ctrl_ops, 9307955f03dSHans Verkuil .id = V4L2_CID_MB_THRESHOLD0, 9317955f03dSHans Verkuil .name = "MB Threshold Region 0", 9327955f03dSHans Verkuil .type = V4L2_CTRL_TYPE_INTEGER, 9337955f03dSHans Verkuil .def = 200, 9347955f03dSHans Verkuil .max = 32767, 9357955f03dSHans Verkuil .step = 1, 9367955f03dSHans Verkuil }; 9377955f03dSHans Verkuil 9387955f03dSHans Verkuil static const struct v4l2_ctrl_config go7007_pixel_threshold1_ctrl = { 9397955f03dSHans Verkuil .ops = &go7007_ctrl_ops, 9407955f03dSHans Verkuil .id = V4L2_CID_PIXEL_THRESHOLD1, 9417955f03dSHans Verkuil .name = "Pixel Threshold Region 1", 9427955f03dSHans Verkuil .type = V4L2_CTRL_TYPE_INTEGER, 9437955f03dSHans Verkuil .def = 20, 9447955f03dSHans Verkuil .max = 32767, 9457955f03dSHans Verkuil .step = 1, 9467955f03dSHans Verkuil }; 9477955f03dSHans Verkuil 9487955f03dSHans Verkuil static const struct v4l2_ctrl_config go7007_motion_threshold1_ctrl = { 9497955f03dSHans Verkuil .ops = &go7007_ctrl_ops, 9507955f03dSHans Verkuil .id = V4L2_CID_MOTION_THRESHOLD1, 9517955f03dSHans Verkuil .name = "Motion Threshold Region 1", 9527955f03dSHans Verkuil .type = V4L2_CTRL_TYPE_INTEGER, 9537955f03dSHans Verkuil .def = 80, 9547955f03dSHans Verkuil .max = 32767, 9557955f03dSHans Verkuil .step = 1, 9567955f03dSHans Verkuil }; 9577955f03dSHans Verkuil 9587955f03dSHans Verkuil static const struct v4l2_ctrl_config go7007_mb_threshold1_ctrl = { 9597955f03dSHans Verkuil .ops = &go7007_ctrl_ops, 9607955f03dSHans Verkuil .id = V4L2_CID_MB_THRESHOLD1, 9617955f03dSHans Verkuil .name = "MB Threshold Region 1", 9627955f03dSHans Verkuil .type = V4L2_CTRL_TYPE_INTEGER, 9637955f03dSHans Verkuil .def = 200, 9647955f03dSHans Verkuil .max = 32767, 9657955f03dSHans Verkuil .step = 1, 9667955f03dSHans Verkuil }; 9677955f03dSHans Verkuil 9687955f03dSHans Verkuil static const struct v4l2_ctrl_config go7007_pixel_threshold2_ctrl = { 9697955f03dSHans Verkuil .ops = &go7007_ctrl_ops, 9707955f03dSHans Verkuil .id = V4L2_CID_PIXEL_THRESHOLD2, 9717955f03dSHans Verkuil .name = "Pixel Threshold Region 2", 9727955f03dSHans Verkuil .type = V4L2_CTRL_TYPE_INTEGER, 9737955f03dSHans Verkuil .def = 20, 9747955f03dSHans Verkuil .max = 32767, 9757955f03dSHans Verkuil .step = 1, 9767955f03dSHans Verkuil }; 9777955f03dSHans Verkuil 9787955f03dSHans Verkuil static const struct v4l2_ctrl_config go7007_motion_threshold2_ctrl = { 9797955f03dSHans Verkuil .ops = &go7007_ctrl_ops, 9807955f03dSHans Verkuil .id = V4L2_CID_MOTION_THRESHOLD2, 9817955f03dSHans Verkuil .name = "Motion Threshold Region 2", 9827955f03dSHans Verkuil .type = V4L2_CTRL_TYPE_INTEGER, 9837955f03dSHans Verkuil .def = 80, 9847955f03dSHans Verkuil .max = 32767, 9857955f03dSHans Verkuil .step = 1, 9867955f03dSHans Verkuil }; 9877955f03dSHans Verkuil 9887955f03dSHans Verkuil static const struct v4l2_ctrl_config go7007_mb_threshold2_ctrl = { 9897955f03dSHans Verkuil .ops = &go7007_ctrl_ops, 9907955f03dSHans Verkuil .id = V4L2_CID_MB_THRESHOLD2, 9917955f03dSHans Verkuil .name = "MB Threshold Region 2", 9927955f03dSHans Verkuil .type = V4L2_CTRL_TYPE_INTEGER, 9937955f03dSHans Verkuil .def = 200, 9947955f03dSHans Verkuil .max = 32767, 9957955f03dSHans Verkuil .step = 1, 9967955f03dSHans Verkuil }; 9977955f03dSHans Verkuil 9987955f03dSHans Verkuil static const struct v4l2_ctrl_config go7007_pixel_threshold3_ctrl = { 9997955f03dSHans Verkuil .ops = &go7007_ctrl_ops, 10007955f03dSHans Verkuil .id = V4L2_CID_PIXEL_THRESHOLD3, 10017955f03dSHans Verkuil .name = "Pixel Threshold Region 3", 10027955f03dSHans Verkuil .type = V4L2_CTRL_TYPE_INTEGER, 10037955f03dSHans Verkuil .def = 20, 10047955f03dSHans Verkuil .max = 32767, 10057955f03dSHans Verkuil .step = 1, 10067955f03dSHans Verkuil }; 10077955f03dSHans Verkuil 10087955f03dSHans Verkuil static const struct v4l2_ctrl_config go7007_motion_threshold3_ctrl = { 10097955f03dSHans Verkuil .ops = &go7007_ctrl_ops, 10107955f03dSHans Verkuil .id = V4L2_CID_MOTION_THRESHOLD3, 10117955f03dSHans Verkuil .name = "Motion Threshold Region 3", 10127955f03dSHans Verkuil .type = V4L2_CTRL_TYPE_INTEGER, 10137955f03dSHans Verkuil .def = 80, 10147955f03dSHans Verkuil .max = 32767, 10157955f03dSHans Verkuil .step = 1, 10167955f03dSHans Verkuil }; 10177955f03dSHans Verkuil 10187955f03dSHans Verkuil static const struct v4l2_ctrl_config go7007_mb_threshold3_ctrl = { 10197955f03dSHans Verkuil .ops = &go7007_ctrl_ops, 10207955f03dSHans Verkuil .id = V4L2_CID_MB_THRESHOLD3, 10217955f03dSHans Verkuil .name = "MB Threshold Region 3", 10227955f03dSHans Verkuil .type = V4L2_CTRL_TYPE_INTEGER, 10237955f03dSHans Verkuil .def = 200, 10247955f03dSHans Verkuil .max = 32767, 10257955f03dSHans Verkuil .step = 1, 10267955f03dSHans Verkuil }; 10277955f03dSHans Verkuil 10287955f03dSHans Verkuil static const struct v4l2_ctrl_config go7007_mb_regions_ctrl = { 10297955f03dSHans Verkuil .ops = &go7007_ctrl_ops, 10307955f03dSHans Verkuil .id = V4L2_CID_DETECT_MD_REGION_GRID, 10317955f03dSHans Verkuil .dims = { 576 / 16, 720 / 16 }, 10327955f03dSHans Verkuil .max = 3, 10337955f03dSHans Verkuil .step = 1, 10347955f03dSHans Verkuil }; 10357955f03dSHans Verkuil 10367955f03dSHans Verkuil int go7007_v4l2_ctrl_init(struct go7007 *go) 10377955f03dSHans Verkuil { 10387955f03dSHans Verkuil struct v4l2_ctrl_handler *hdl = &go->hdl; 10397955f03dSHans Verkuil struct v4l2_ctrl *ctrl; 10407955f03dSHans Verkuil 10417955f03dSHans Verkuil v4l2_ctrl_handler_init(hdl, 22); 10427955f03dSHans Verkuil go->mpeg_video_gop_size = v4l2_ctrl_new_std(hdl, NULL, 10437955f03dSHans Verkuil V4L2_CID_MPEG_VIDEO_GOP_SIZE, 0, 34, 1, 15); 10447955f03dSHans Verkuil go->mpeg_video_gop_closure = v4l2_ctrl_new_std(hdl, NULL, 10457955f03dSHans Verkuil V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, 0, 1, 1, 1); 10467955f03dSHans Verkuil go->mpeg_video_bitrate = v4l2_ctrl_new_std(hdl, NULL, 10477955f03dSHans Verkuil V4L2_CID_MPEG_VIDEO_BITRATE, 10487955f03dSHans Verkuil 64000, 10000000, 1, 9800000); 10497955f03dSHans Verkuil go->mpeg_video_b_frames = v4l2_ctrl_new_std(hdl, NULL, 10507955f03dSHans Verkuil V4L2_CID_MPEG_VIDEO_B_FRAMES, 0, 2, 2, 0); 10517955f03dSHans Verkuil go->mpeg_video_rep_seqheader = v4l2_ctrl_new_std(hdl, NULL, 10527955f03dSHans Verkuil V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER, 0, 1, 1, 1); 10537955f03dSHans Verkuil 10547955f03dSHans Verkuil go->mpeg_video_aspect_ratio = v4l2_ctrl_new_std_menu(hdl, NULL, 10557955f03dSHans Verkuil V4L2_CID_MPEG_VIDEO_ASPECT, 10567955f03dSHans Verkuil V4L2_MPEG_VIDEO_ASPECT_16x9, 0, 10577955f03dSHans Verkuil V4L2_MPEG_VIDEO_ASPECT_1x1); 10587955f03dSHans Verkuil ctrl = v4l2_ctrl_new_std(hdl, NULL, 10597955f03dSHans Verkuil V4L2_CID_JPEG_ACTIVE_MARKER, 0, 10607955f03dSHans Verkuil V4L2_JPEG_ACTIVE_MARKER_DQT | 10617955f03dSHans Verkuil V4L2_JPEG_ACTIVE_MARKER_DHT, 0, 10627955f03dSHans Verkuil V4L2_JPEG_ACTIVE_MARKER_DQT | 10637955f03dSHans Verkuil V4L2_JPEG_ACTIVE_MARKER_DHT); 10647955f03dSHans Verkuil if (ctrl) 10657955f03dSHans Verkuil ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; 10667955f03dSHans Verkuil v4l2_ctrl_new_custom(hdl, &go7007_pixel_threshold0_ctrl, NULL); 10677955f03dSHans Verkuil v4l2_ctrl_new_custom(hdl, &go7007_motion_threshold0_ctrl, NULL); 10687955f03dSHans Verkuil v4l2_ctrl_new_custom(hdl, &go7007_mb_threshold0_ctrl, NULL); 10697955f03dSHans Verkuil v4l2_ctrl_new_custom(hdl, &go7007_pixel_threshold1_ctrl, NULL); 10707955f03dSHans Verkuil v4l2_ctrl_new_custom(hdl, &go7007_motion_threshold1_ctrl, NULL); 10717955f03dSHans Verkuil v4l2_ctrl_new_custom(hdl, &go7007_mb_threshold1_ctrl, NULL); 10727955f03dSHans Verkuil v4l2_ctrl_new_custom(hdl, &go7007_pixel_threshold2_ctrl, NULL); 10737955f03dSHans Verkuil v4l2_ctrl_new_custom(hdl, &go7007_motion_threshold2_ctrl, NULL); 10747955f03dSHans Verkuil v4l2_ctrl_new_custom(hdl, &go7007_mb_threshold2_ctrl, NULL); 10757955f03dSHans Verkuil v4l2_ctrl_new_custom(hdl, &go7007_pixel_threshold3_ctrl, NULL); 10767955f03dSHans Verkuil v4l2_ctrl_new_custom(hdl, &go7007_motion_threshold3_ctrl, NULL); 10777955f03dSHans Verkuil v4l2_ctrl_new_custom(hdl, &go7007_mb_threshold3_ctrl, NULL); 10787955f03dSHans Verkuil v4l2_ctrl_new_custom(hdl, &go7007_mb_regions_ctrl, NULL); 10797955f03dSHans Verkuil go->modet_mode = v4l2_ctrl_new_std_menu(hdl, NULL, 10807955f03dSHans Verkuil V4L2_CID_DETECT_MD_MODE, 10817955f03dSHans Verkuil V4L2_DETECT_MD_MODE_REGION_GRID, 10827955f03dSHans Verkuil 1 << V4L2_DETECT_MD_MODE_THRESHOLD_GRID, 10837955f03dSHans Verkuil V4L2_DETECT_MD_MODE_DISABLED); 10847955f03dSHans Verkuil if (hdl->error) { 10857955f03dSHans Verkuil int rv = hdl->error; 10867955f03dSHans Verkuil 10877955f03dSHans Verkuil v4l2_err(&go->v4l2_dev, "Could not register controls\n"); 10887955f03dSHans Verkuil return rv; 10897955f03dSHans Verkuil } 10907955f03dSHans Verkuil go->v4l2_dev.ctrl_handler = hdl; 10917955f03dSHans Verkuil return 0; 10927955f03dSHans Verkuil } 10937955f03dSHans Verkuil 10947955f03dSHans Verkuil int go7007_v4l2_init(struct go7007 *go) 10957955f03dSHans Verkuil { 10967955f03dSHans Verkuil struct video_device *vdev = &go->vdev; 10977955f03dSHans Verkuil int rv; 10987955f03dSHans Verkuil 10997955f03dSHans Verkuil mutex_init(&go->serialize_lock); 11007955f03dSHans Verkuil mutex_init(&go->queue_lock); 11017955f03dSHans Verkuil 11027955f03dSHans Verkuil INIT_LIST_HEAD(&go->vidq_active); 11037955f03dSHans Verkuil go->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 11047955f03dSHans Verkuil go->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; 11057955f03dSHans Verkuil go->vidq.ops = &go7007_video_qops; 11067955f03dSHans Verkuil go->vidq.mem_ops = &vb2_vmalloc_memops; 11077955f03dSHans Verkuil go->vidq.drv_priv = go; 11087955f03dSHans Verkuil go->vidq.buf_struct_size = sizeof(struct go7007_buffer); 11097955f03dSHans Verkuil go->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; 11107955f03dSHans Verkuil go->vidq.lock = &go->queue_lock; 11117955f03dSHans Verkuil rv = vb2_queue_init(&go->vidq); 11127955f03dSHans Verkuil if (rv) 11137955f03dSHans Verkuil return rv; 11147955f03dSHans Verkuil *vdev = go7007_template; 11157955f03dSHans Verkuil vdev->lock = &go->serialize_lock; 11167955f03dSHans Verkuil vdev->queue = &go->vidq; 11177955f03dSHans Verkuil video_set_drvdata(vdev, go); 11187955f03dSHans Verkuil vdev->v4l2_dev = &go->v4l2_dev; 111996655553SHans Verkuil if (!v4l2_device_has_op(&go->v4l2_dev, 0, video, querystd)) 11207955f03dSHans Verkuil v4l2_disable_ioctl(vdev, VIDIOC_QUERYSTD); 11217955f03dSHans Verkuil if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER)) { 11227955f03dSHans Verkuil v4l2_disable_ioctl(vdev, VIDIOC_S_FREQUENCY); 11237955f03dSHans Verkuil v4l2_disable_ioctl(vdev, VIDIOC_G_FREQUENCY); 11247955f03dSHans Verkuil v4l2_disable_ioctl(vdev, VIDIOC_S_TUNER); 11257955f03dSHans Verkuil v4l2_disable_ioctl(vdev, VIDIOC_G_TUNER); 11267955f03dSHans Verkuil } else { 11277955f03dSHans Verkuil struct v4l2_frequency f = { 11287955f03dSHans Verkuil .type = V4L2_TUNER_ANALOG_TV, 11297955f03dSHans Verkuil .frequency = 980, 11307955f03dSHans Verkuil }; 11317955f03dSHans Verkuil 11327955f03dSHans Verkuil call_all(&go->v4l2_dev, tuner, s_frequency, &f); 11337955f03dSHans Verkuil } 11347955f03dSHans Verkuil if (!(go->board_info->sensor_flags & GO7007_SENSOR_TV)) { 11357955f03dSHans Verkuil v4l2_disable_ioctl(vdev, VIDIOC_G_STD); 11367955f03dSHans Verkuil v4l2_disable_ioctl(vdev, VIDIOC_S_STD); 11377955f03dSHans Verkuil vdev->tvnorms = 0; 11387955f03dSHans Verkuil } 11397955f03dSHans Verkuil if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING) 11407955f03dSHans Verkuil v4l2_disable_ioctl(vdev, VIDIOC_ENUM_FRAMESIZES); 11417955f03dSHans Verkuil if (go->board_info->num_aud_inputs == 0) { 11427955f03dSHans Verkuil v4l2_disable_ioctl(vdev, VIDIOC_G_AUDIO); 11437955f03dSHans Verkuil v4l2_disable_ioctl(vdev, VIDIOC_S_AUDIO); 11447955f03dSHans Verkuil v4l2_disable_ioctl(vdev, VIDIOC_ENUMAUDIO); 11457955f03dSHans Verkuil } 11467955f03dSHans Verkuil /* Setup correct crystal frequency on this board */ 11477955f03dSHans Verkuil if (go->board_info->sensor_flags & GO7007_SENSOR_SAA7115) 11487955f03dSHans Verkuil v4l2_subdev_call(go->sd_video, video, s_crystal_freq, 11497955f03dSHans Verkuil SAA7115_FREQ_24_576_MHZ, 11507955f03dSHans Verkuil SAA7115_FREQ_FL_APLL | SAA7115_FREQ_FL_UCGC | 11517955f03dSHans Verkuil SAA7115_FREQ_FL_DOUBLE_ASCLK); 11527955f03dSHans Verkuil go7007_s_input(go); 11537955f03dSHans Verkuil if (go->board_info->sensor_flags & GO7007_SENSOR_TV) 11547955f03dSHans Verkuil go7007_s_std(go); 11557955f03dSHans Verkuil rv = video_register_device(vdev, VFL_TYPE_GRABBER, -1); 11567955f03dSHans Verkuil if (rv < 0) 11577955f03dSHans Verkuil return rv; 11587955f03dSHans Verkuil dev_info(go->dev, "registered device %s [v4l2]\n", 11597955f03dSHans Verkuil video_device_node_name(vdev)); 11607955f03dSHans Verkuil 11617955f03dSHans Verkuil return 0; 11627955f03dSHans Verkuil } 11637955f03dSHans Verkuil 11647955f03dSHans Verkuil void go7007_v4l2_remove(struct go7007 *go) 11657955f03dSHans Verkuil { 11667955f03dSHans Verkuil v4l2_ctrl_handler_free(&go->hdl); 11677955f03dSHans Verkuil } 1168