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