1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) 2005-2006 Micronas USA Inc.
4*4882a593Smuzhiyun */
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun #include <linux/module.h>
7*4882a593Smuzhiyun #include <linux/delay.h>
8*4882a593Smuzhiyun #include <linux/sched.h>
9*4882a593Smuzhiyun #include <linux/spinlock.h>
10*4882a593Smuzhiyun #include <linux/slab.h>
11*4882a593Smuzhiyun #include <linux/fs.h>
12*4882a593Smuzhiyun #include <linux/unistd.h>
13*4882a593Smuzhiyun #include <linux/time.h>
14*4882a593Smuzhiyun #include <linux/vmalloc.h>
15*4882a593Smuzhiyun #include <linux/pagemap.h>
16*4882a593Smuzhiyun #include <linux/i2c.h>
17*4882a593Smuzhiyun #include <linux/mutex.h>
18*4882a593Smuzhiyun #include <linux/uaccess.h>
19*4882a593Smuzhiyun #include <linux/videodev2.h>
20*4882a593Smuzhiyun #include <media/v4l2-common.h>
21*4882a593Smuzhiyun #include <media/v4l2-ioctl.h>
22*4882a593Smuzhiyun #include <media/v4l2-subdev.h>
23*4882a593Smuzhiyun #include <media/v4l2-event.h>
24*4882a593Smuzhiyun #include <media/videobuf2-vmalloc.h>
25*4882a593Smuzhiyun #include <media/i2c/saa7115.h>
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun #include "go7007-priv.h"
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun #define call_all(dev, o, f, args...) \
30*4882a593Smuzhiyun v4l2_device_call_until_err(dev, 0, o, f, ##args)
31*4882a593Smuzhiyun
valid_pixelformat(u32 pixelformat)32*4882a593Smuzhiyun static bool valid_pixelformat(u32 pixelformat)
33*4882a593Smuzhiyun {
34*4882a593Smuzhiyun switch (pixelformat) {
35*4882a593Smuzhiyun case V4L2_PIX_FMT_MJPEG:
36*4882a593Smuzhiyun case V4L2_PIX_FMT_MPEG1:
37*4882a593Smuzhiyun case V4L2_PIX_FMT_MPEG2:
38*4882a593Smuzhiyun case V4L2_PIX_FMT_MPEG4:
39*4882a593Smuzhiyun return true;
40*4882a593Smuzhiyun default:
41*4882a593Smuzhiyun return false;
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun
get_frame_type_flag(struct go7007_buffer * vb,int format)45*4882a593Smuzhiyun static u32 get_frame_type_flag(struct go7007_buffer *vb, int format)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun u8 *ptr = vb2_plane_vaddr(&vb->vb.vb2_buf, 0);
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun switch (format) {
50*4882a593Smuzhiyun case V4L2_PIX_FMT_MJPEG:
51*4882a593Smuzhiyun return V4L2_BUF_FLAG_KEYFRAME;
52*4882a593Smuzhiyun case V4L2_PIX_FMT_MPEG4:
53*4882a593Smuzhiyun switch ((ptr[vb->frame_offset + 4] >> 6) & 0x3) {
54*4882a593Smuzhiyun case 0:
55*4882a593Smuzhiyun return V4L2_BUF_FLAG_KEYFRAME;
56*4882a593Smuzhiyun case 1:
57*4882a593Smuzhiyun return V4L2_BUF_FLAG_PFRAME;
58*4882a593Smuzhiyun case 2:
59*4882a593Smuzhiyun return V4L2_BUF_FLAG_BFRAME;
60*4882a593Smuzhiyun default:
61*4882a593Smuzhiyun return 0;
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun case V4L2_PIX_FMT_MPEG1:
64*4882a593Smuzhiyun case V4L2_PIX_FMT_MPEG2:
65*4882a593Smuzhiyun switch ((ptr[vb->frame_offset + 5] >> 3) & 0x7) {
66*4882a593Smuzhiyun case 1:
67*4882a593Smuzhiyun return V4L2_BUF_FLAG_KEYFRAME;
68*4882a593Smuzhiyun case 2:
69*4882a593Smuzhiyun return V4L2_BUF_FLAG_PFRAME;
70*4882a593Smuzhiyun case 3:
71*4882a593Smuzhiyun return V4L2_BUF_FLAG_BFRAME;
72*4882a593Smuzhiyun default:
73*4882a593Smuzhiyun return 0;
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun return 0;
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun
get_resolution(struct go7007 * go,int * width,int * height)80*4882a593Smuzhiyun static void get_resolution(struct go7007 *go, int *width, int *height)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun switch (go->standard) {
83*4882a593Smuzhiyun case GO7007_STD_NTSC:
84*4882a593Smuzhiyun *width = 720;
85*4882a593Smuzhiyun *height = 480;
86*4882a593Smuzhiyun break;
87*4882a593Smuzhiyun case GO7007_STD_PAL:
88*4882a593Smuzhiyun *width = 720;
89*4882a593Smuzhiyun *height = 576;
90*4882a593Smuzhiyun break;
91*4882a593Smuzhiyun case GO7007_STD_OTHER:
92*4882a593Smuzhiyun default:
93*4882a593Smuzhiyun *width = go->board_info->sensor_width;
94*4882a593Smuzhiyun *height = go->board_info->sensor_height;
95*4882a593Smuzhiyun break;
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun
set_formatting(struct go7007 * go)99*4882a593Smuzhiyun static void set_formatting(struct go7007 *go)
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun if (go->format == V4L2_PIX_FMT_MJPEG) {
102*4882a593Smuzhiyun go->pali = 0;
103*4882a593Smuzhiyun go->aspect_ratio = GO7007_RATIO_1_1;
104*4882a593Smuzhiyun go->gop_size = 0;
105*4882a593Smuzhiyun go->ipb = 0;
106*4882a593Smuzhiyun go->closed_gop = 0;
107*4882a593Smuzhiyun go->repeat_seqhead = 0;
108*4882a593Smuzhiyun go->seq_header_enable = 0;
109*4882a593Smuzhiyun go->gop_header_enable = 0;
110*4882a593Smuzhiyun go->dvd_mode = 0;
111*4882a593Smuzhiyun return;
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun switch (go->format) {
115*4882a593Smuzhiyun case V4L2_PIX_FMT_MPEG1:
116*4882a593Smuzhiyun go->pali = 0;
117*4882a593Smuzhiyun break;
118*4882a593Smuzhiyun default:
119*4882a593Smuzhiyun case V4L2_PIX_FMT_MPEG2:
120*4882a593Smuzhiyun go->pali = 0x48;
121*4882a593Smuzhiyun break;
122*4882a593Smuzhiyun case V4L2_PIX_FMT_MPEG4:
123*4882a593Smuzhiyun /* For future reference: this is the list of MPEG4
124*4882a593Smuzhiyun * profiles that are available, although they are
125*4882a593Smuzhiyun * untested:
126*4882a593Smuzhiyun *
127*4882a593Smuzhiyun * Profile pali
128*4882a593Smuzhiyun * -------------- ----
129*4882a593Smuzhiyun * PROFILE_S_L0 0x08
130*4882a593Smuzhiyun * PROFILE_S_L1 0x01
131*4882a593Smuzhiyun * PROFILE_S_L2 0x02
132*4882a593Smuzhiyun * PROFILE_S_L3 0x03
133*4882a593Smuzhiyun * PROFILE_ARTS_L1 0x91
134*4882a593Smuzhiyun * PROFILE_ARTS_L2 0x92
135*4882a593Smuzhiyun * PROFILE_ARTS_L3 0x93
136*4882a593Smuzhiyun * PROFILE_ARTS_L4 0x94
137*4882a593Smuzhiyun * PROFILE_AS_L0 0xf0
138*4882a593Smuzhiyun * PROFILE_AS_L1 0xf1
139*4882a593Smuzhiyun * PROFILE_AS_L2 0xf2
140*4882a593Smuzhiyun * PROFILE_AS_L3 0xf3
141*4882a593Smuzhiyun * PROFILE_AS_L4 0xf4
142*4882a593Smuzhiyun * PROFILE_AS_L5 0xf5
143*4882a593Smuzhiyun */
144*4882a593Smuzhiyun go->pali = 0xf5;
145*4882a593Smuzhiyun break;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun go->gop_size = v4l2_ctrl_g_ctrl(go->mpeg_video_gop_size);
148*4882a593Smuzhiyun go->closed_gop = v4l2_ctrl_g_ctrl(go->mpeg_video_gop_closure);
149*4882a593Smuzhiyun go->ipb = v4l2_ctrl_g_ctrl(go->mpeg_video_b_frames) != 0;
150*4882a593Smuzhiyun go->bitrate = v4l2_ctrl_g_ctrl(go->mpeg_video_bitrate);
151*4882a593Smuzhiyun go->repeat_seqhead = v4l2_ctrl_g_ctrl(go->mpeg_video_rep_seqheader);
152*4882a593Smuzhiyun go->gop_header_enable = 1;
153*4882a593Smuzhiyun go->dvd_mode = 0;
154*4882a593Smuzhiyun if (go->format == V4L2_PIX_FMT_MPEG2)
155*4882a593Smuzhiyun go->dvd_mode =
156*4882a593Smuzhiyun go->bitrate == 9800000 &&
157*4882a593Smuzhiyun go->gop_size == 15 &&
158*4882a593Smuzhiyun go->ipb == 0 &&
159*4882a593Smuzhiyun go->repeat_seqhead == 1 &&
160*4882a593Smuzhiyun go->closed_gop;
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun switch (v4l2_ctrl_g_ctrl(go->mpeg_video_aspect_ratio)) {
163*4882a593Smuzhiyun default:
164*4882a593Smuzhiyun case V4L2_MPEG_VIDEO_ASPECT_1x1:
165*4882a593Smuzhiyun go->aspect_ratio = GO7007_RATIO_1_1;
166*4882a593Smuzhiyun break;
167*4882a593Smuzhiyun case V4L2_MPEG_VIDEO_ASPECT_4x3:
168*4882a593Smuzhiyun go->aspect_ratio = GO7007_RATIO_4_3;
169*4882a593Smuzhiyun break;
170*4882a593Smuzhiyun case V4L2_MPEG_VIDEO_ASPECT_16x9:
171*4882a593Smuzhiyun go->aspect_ratio = GO7007_RATIO_16_9;
172*4882a593Smuzhiyun break;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun
set_capture_size(struct go7007 * go,struct v4l2_format * fmt,int try)176*4882a593Smuzhiyun static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try)
177*4882a593Smuzhiyun {
178*4882a593Smuzhiyun int sensor_height = 0, sensor_width = 0;
179*4882a593Smuzhiyun int width, height;
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun if (fmt != NULL && !valid_pixelformat(fmt->fmt.pix.pixelformat))
182*4882a593Smuzhiyun return -EINVAL;
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun get_resolution(go, &sensor_width, &sensor_height);
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun if (fmt == NULL) {
187*4882a593Smuzhiyun width = sensor_width;
188*4882a593Smuzhiyun height = sensor_height;
189*4882a593Smuzhiyun } else if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING) {
190*4882a593Smuzhiyun if (fmt->fmt.pix.width > sensor_width)
191*4882a593Smuzhiyun width = sensor_width;
192*4882a593Smuzhiyun else if (fmt->fmt.pix.width < 144)
193*4882a593Smuzhiyun width = 144;
194*4882a593Smuzhiyun else
195*4882a593Smuzhiyun width = fmt->fmt.pix.width & ~0x0f;
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun if (fmt->fmt.pix.height > sensor_height)
198*4882a593Smuzhiyun height = sensor_height;
199*4882a593Smuzhiyun else if (fmt->fmt.pix.height < 96)
200*4882a593Smuzhiyun height = 96;
201*4882a593Smuzhiyun else
202*4882a593Smuzhiyun height = fmt->fmt.pix.height & ~0x0f;
203*4882a593Smuzhiyun } else {
204*4882a593Smuzhiyun width = fmt->fmt.pix.width;
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun if (width <= sensor_width / 4) {
207*4882a593Smuzhiyun width = sensor_width / 4;
208*4882a593Smuzhiyun height = sensor_height / 4;
209*4882a593Smuzhiyun } else if (width <= sensor_width / 2) {
210*4882a593Smuzhiyun width = sensor_width / 2;
211*4882a593Smuzhiyun height = sensor_height / 2;
212*4882a593Smuzhiyun } else {
213*4882a593Smuzhiyun width = sensor_width;
214*4882a593Smuzhiyun height = sensor_height;
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun width &= ~0xf;
217*4882a593Smuzhiyun height &= ~0xf;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun if (fmt != NULL) {
221*4882a593Smuzhiyun u32 pixelformat = fmt->fmt.pix.pixelformat;
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun memset(fmt, 0, sizeof(*fmt));
224*4882a593Smuzhiyun fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
225*4882a593Smuzhiyun fmt->fmt.pix.width = width;
226*4882a593Smuzhiyun fmt->fmt.pix.height = height;
227*4882a593Smuzhiyun fmt->fmt.pix.pixelformat = pixelformat;
228*4882a593Smuzhiyun fmt->fmt.pix.field = V4L2_FIELD_NONE;
229*4882a593Smuzhiyun fmt->fmt.pix.bytesperline = 0;
230*4882a593Smuzhiyun fmt->fmt.pix.sizeimage = GO7007_BUF_SIZE;
231*4882a593Smuzhiyun fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun if (try)
235*4882a593Smuzhiyun return 0;
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun if (fmt)
238*4882a593Smuzhiyun go->format = fmt->fmt.pix.pixelformat;
239*4882a593Smuzhiyun go->width = width;
240*4882a593Smuzhiyun go->height = height;
241*4882a593Smuzhiyun go->encoder_h_offset = go->board_info->sensor_h_offset;
242*4882a593Smuzhiyun go->encoder_v_offset = go->board_info->sensor_v_offset;
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING) {
245*4882a593Smuzhiyun struct v4l2_subdev_format format = {
246*4882a593Smuzhiyun .which = V4L2_SUBDEV_FORMAT_ACTIVE,
247*4882a593Smuzhiyun };
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun format.format.code = MEDIA_BUS_FMT_FIXED;
250*4882a593Smuzhiyun format.format.width = fmt ? fmt->fmt.pix.width : width;
251*4882a593Smuzhiyun format.format.height = height;
252*4882a593Smuzhiyun go->encoder_h_halve = 0;
253*4882a593Smuzhiyun go->encoder_v_halve = 0;
254*4882a593Smuzhiyun go->encoder_subsample = 0;
255*4882a593Smuzhiyun call_all(&go->v4l2_dev, pad, set_fmt, NULL, &format);
256*4882a593Smuzhiyun } else {
257*4882a593Smuzhiyun if (width <= sensor_width / 4) {
258*4882a593Smuzhiyun go->encoder_h_halve = 1;
259*4882a593Smuzhiyun go->encoder_v_halve = 1;
260*4882a593Smuzhiyun go->encoder_subsample = 1;
261*4882a593Smuzhiyun } else if (width <= sensor_width / 2) {
262*4882a593Smuzhiyun go->encoder_h_halve = 1;
263*4882a593Smuzhiyun go->encoder_v_halve = 1;
264*4882a593Smuzhiyun go->encoder_subsample = 0;
265*4882a593Smuzhiyun } else {
266*4882a593Smuzhiyun go->encoder_h_halve = 0;
267*4882a593Smuzhiyun go->encoder_v_halve = 0;
268*4882a593Smuzhiyun go->encoder_subsample = 0;
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun return 0;
272*4882a593Smuzhiyun }
273*4882a593Smuzhiyun
vidioc_querycap(struct file * file,void * priv,struct v4l2_capability * cap)274*4882a593Smuzhiyun static int vidioc_querycap(struct file *file, void *priv,
275*4882a593Smuzhiyun struct v4l2_capability *cap)
276*4882a593Smuzhiyun {
277*4882a593Smuzhiyun struct go7007 *go = video_drvdata(file);
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun strscpy(cap->driver, "go7007", sizeof(cap->driver));
280*4882a593Smuzhiyun strscpy(cap->card, go->name, sizeof(cap->card));
281*4882a593Smuzhiyun strscpy(cap->bus_info, go->bus_info, sizeof(cap->bus_info));
282*4882a593Smuzhiyun return 0;
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun
vidioc_enum_fmt_vid_cap(struct file * file,void * priv,struct v4l2_fmtdesc * fmt)285*4882a593Smuzhiyun static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
286*4882a593Smuzhiyun struct v4l2_fmtdesc *fmt)
287*4882a593Smuzhiyun {
288*4882a593Smuzhiyun switch (fmt->index) {
289*4882a593Smuzhiyun case 0:
290*4882a593Smuzhiyun fmt->pixelformat = V4L2_PIX_FMT_MJPEG;
291*4882a593Smuzhiyun break;
292*4882a593Smuzhiyun case 1:
293*4882a593Smuzhiyun fmt->pixelformat = V4L2_PIX_FMT_MPEG1;
294*4882a593Smuzhiyun break;
295*4882a593Smuzhiyun case 2:
296*4882a593Smuzhiyun fmt->pixelformat = V4L2_PIX_FMT_MPEG2;
297*4882a593Smuzhiyun break;
298*4882a593Smuzhiyun case 3:
299*4882a593Smuzhiyun fmt->pixelformat = V4L2_PIX_FMT_MPEG4;
300*4882a593Smuzhiyun break;
301*4882a593Smuzhiyun default:
302*4882a593Smuzhiyun return -EINVAL;
303*4882a593Smuzhiyun }
304*4882a593Smuzhiyun return 0;
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun
vidioc_g_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * fmt)307*4882a593Smuzhiyun static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
308*4882a593Smuzhiyun struct v4l2_format *fmt)
309*4882a593Smuzhiyun {
310*4882a593Smuzhiyun struct go7007 *go = video_drvdata(file);
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
313*4882a593Smuzhiyun fmt->fmt.pix.width = go->width;
314*4882a593Smuzhiyun fmt->fmt.pix.height = go->height;
315*4882a593Smuzhiyun fmt->fmt.pix.pixelformat = go->format;
316*4882a593Smuzhiyun fmt->fmt.pix.field = V4L2_FIELD_NONE;
317*4882a593Smuzhiyun fmt->fmt.pix.bytesperline = 0;
318*4882a593Smuzhiyun fmt->fmt.pix.sizeimage = GO7007_BUF_SIZE;
319*4882a593Smuzhiyun fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun return 0;
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun
vidioc_try_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * fmt)324*4882a593Smuzhiyun static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
325*4882a593Smuzhiyun struct v4l2_format *fmt)
326*4882a593Smuzhiyun {
327*4882a593Smuzhiyun struct go7007 *go = video_drvdata(file);
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun return set_capture_size(go, fmt, 1);
330*4882a593Smuzhiyun }
331*4882a593Smuzhiyun
vidioc_s_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * fmt)332*4882a593Smuzhiyun static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
333*4882a593Smuzhiyun struct v4l2_format *fmt)
334*4882a593Smuzhiyun {
335*4882a593Smuzhiyun struct go7007 *go = video_drvdata(file);
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun if (vb2_is_busy(&go->vidq))
338*4882a593Smuzhiyun return -EBUSY;
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun return set_capture_size(go, fmt, 0);
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun
go7007_queue_setup(struct vb2_queue * q,unsigned int * num_buffers,unsigned int * num_planes,unsigned int sizes[],struct device * alloc_devs[])343*4882a593Smuzhiyun static int go7007_queue_setup(struct vb2_queue *q,
344*4882a593Smuzhiyun unsigned int *num_buffers, unsigned int *num_planes,
345*4882a593Smuzhiyun unsigned int sizes[], struct device *alloc_devs[])
346*4882a593Smuzhiyun {
347*4882a593Smuzhiyun sizes[0] = GO7007_BUF_SIZE;
348*4882a593Smuzhiyun *num_planes = 1;
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun if (*num_buffers < 2)
351*4882a593Smuzhiyun *num_buffers = 2;
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun return 0;
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun
go7007_buf_queue(struct vb2_buffer * vb)356*4882a593Smuzhiyun static void go7007_buf_queue(struct vb2_buffer *vb)
357*4882a593Smuzhiyun {
358*4882a593Smuzhiyun struct vb2_queue *vq = vb->vb2_queue;
359*4882a593Smuzhiyun struct go7007 *go = vb2_get_drv_priv(vq);
360*4882a593Smuzhiyun struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
361*4882a593Smuzhiyun struct go7007_buffer *go7007_vb =
362*4882a593Smuzhiyun container_of(vbuf, struct go7007_buffer, vb);
363*4882a593Smuzhiyun unsigned long flags;
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun spin_lock_irqsave(&go->spinlock, flags);
366*4882a593Smuzhiyun list_add_tail(&go7007_vb->list, &go->vidq_active);
367*4882a593Smuzhiyun spin_unlock_irqrestore(&go->spinlock, flags);
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun
go7007_buf_prepare(struct vb2_buffer * vb)370*4882a593Smuzhiyun static int go7007_buf_prepare(struct vb2_buffer *vb)
371*4882a593Smuzhiyun {
372*4882a593Smuzhiyun struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
373*4882a593Smuzhiyun struct go7007_buffer *go7007_vb =
374*4882a593Smuzhiyun container_of(vbuf, struct go7007_buffer, vb);
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun go7007_vb->modet_active = 0;
377*4882a593Smuzhiyun go7007_vb->frame_offset = 0;
378*4882a593Smuzhiyun vb->planes[0].bytesused = 0;
379*4882a593Smuzhiyun return 0;
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun
go7007_buf_finish(struct vb2_buffer * vb)382*4882a593Smuzhiyun static void go7007_buf_finish(struct vb2_buffer *vb)
383*4882a593Smuzhiyun {
384*4882a593Smuzhiyun struct vb2_queue *vq = vb->vb2_queue;
385*4882a593Smuzhiyun struct go7007 *go = vb2_get_drv_priv(vq);
386*4882a593Smuzhiyun struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
387*4882a593Smuzhiyun struct go7007_buffer *go7007_vb =
388*4882a593Smuzhiyun container_of(vbuf, struct go7007_buffer, vb);
389*4882a593Smuzhiyun u32 frame_type_flag = get_frame_type_flag(go7007_vb, go->format);
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun vbuf->flags &= ~(V4L2_BUF_FLAG_KEYFRAME | V4L2_BUF_FLAG_BFRAME |
392*4882a593Smuzhiyun V4L2_BUF_FLAG_PFRAME);
393*4882a593Smuzhiyun vbuf->flags |= frame_type_flag;
394*4882a593Smuzhiyun vbuf->field = V4L2_FIELD_NONE;
395*4882a593Smuzhiyun }
396*4882a593Smuzhiyun
go7007_start_streaming(struct vb2_queue * q,unsigned int count)397*4882a593Smuzhiyun static int go7007_start_streaming(struct vb2_queue *q, unsigned int count)
398*4882a593Smuzhiyun {
399*4882a593Smuzhiyun struct go7007 *go = vb2_get_drv_priv(q);
400*4882a593Smuzhiyun int ret;
401*4882a593Smuzhiyun
402*4882a593Smuzhiyun set_formatting(go);
403*4882a593Smuzhiyun mutex_lock(&go->hw_lock);
404*4882a593Smuzhiyun go->next_seq = 0;
405*4882a593Smuzhiyun go->active_buf = NULL;
406*4882a593Smuzhiyun go->modet_event_status = 0;
407*4882a593Smuzhiyun q->streaming = 1;
408*4882a593Smuzhiyun if (go7007_start_encoder(go) < 0)
409*4882a593Smuzhiyun ret = -EIO;
410*4882a593Smuzhiyun else
411*4882a593Smuzhiyun ret = 0;
412*4882a593Smuzhiyun mutex_unlock(&go->hw_lock);
413*4882a593Smuzhiyun if (ret) {
414*4882a593Smuzhiyun q->streaming = 0;
415*4882a593Smuzhiyun return ret;
416*4882a593Smuzhiyun }
417*4882a593Smuzhiyun call_all(&go->v4l2_dev, video, s_stream, 1);
418*4882a593Smuzhiyun v4l2_ctrl_grab(go->mpeg_video_gop_size, true);
419*4882a593Smuzhiyun v4l2_ctrl_grab(go->mpeg_video_gop_closure, true);
420*4882a593Smuzhiyun v4l2_ctrl_grab(go->mpeg_video_bitrate, true);
421*4882a593Smuzhiyun v4l2_ctrl_grab(go->mpeg_video_aspect_ratio, true);
422*4882a593Smuzhiyun /* Turn on Capture LED */
423*4882a593Smuzhiyun if (go->board_id == GO7007_BOARDID_ADS_USBAV_709)
424*4882a593Smuzhiyun go7007_write_addr(go, 0x3c82, 0x0005);
425*4882a593Smuzhiyun return ret;
426*4882a593Smuzhiyun }
427*4882a593Smuzhiyun
go7007_stop_streaming(struct vb2_queue * q)428*4882a593Smuzhiyun static void go7007_stop_streaming(struct vb2_queue *q)
429*4882a593Smuzhiyun {
430*4882a593Smuzhiyun struct go7007 *go = vb2_get_drv_priv(q);
431*4882a593Smuzhiyun unsigned long flags;
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun q->streaming = 0;
434*4882a593Smuzhiyun go7007_stream_stop(go);
435*4882a593Smuzhiyun mutex_lock(&go->hw_lock);
436*4882a593Smuzhiyun go7007_reset_encoder(go);
437*4882a593Smuzhiyun mutex_unlock(&go->hw_lock);
438*4882a593Smuzhiyun call_all(&go->v4l2_dev, video, s_stream, 0);
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun spin_lock_irqsave(&go->spinlock, flags);
441*4882a593Smuzhiyun INIT_LIST_HEAD(&go->vidq_active);
442*4882a593Smuzhiyun spin_unlock_irqrestore(&go->spinlock, flags);
443*4882a593Smuzhiyun v4l2_ctrl_grab(go->mpeg_video_gop_size, false);
444*4882a593Smuzhiyun v4l2_ctrl_grab(go->mpeg_video_gop_closure, false);
445*4882a593Smuzhiyun v4l2_ctrl_grab(go->mpeg_video_bitrate, false);
446*4882a593Smuzhiyun v4l2_ctrl_grab(go->mpeg_video_aspect_ratio, false);
447*4882a593Smuzhiyun /* Turn on Capture LED */
448*4882a593Smuzhiyun if (go->board_id == GO7007_BOARDID_ADS_USBAV_709)
449*4882a593Smuzhiyun go7007_write_addr(go, 0x3c82, 0x000d);
450*4882a593Smuzhiyun }
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun static const struct vb2_ops go7007_video_qops = {
453*4882a593Smuzhiyun .queue_setup = go7007_queue_setup,
454*4882a593Smuzhiyun .buf_queue = go7007_buf_queue,
455*4882a593Smuzhiyun .buf_prepare = go7007_buf_prepare,
456*4882a593Smuzhiyun .buf_finish = go7007_buf_finish,
457*4882a593Smuzhiyun .start_streaming = go7007_start_streaming,
458*4882a593Smuzhiyun .stop_streaming = go7007_stop_streaming,
459*4882a593Smuzhiyun .wait_prepare = vb2_ops_wait_prepare,
460*4882a593Smuzhiyun .wait_finish = vb2_ops_wait_finish,
461*4882a593Smuzhiyun };
462*4882a593Smuzhiyun
vidioc_g_parm(struct file * filp,void * priv,struct v4l2_streamparm * parm)463*4882a593Smuzhiyun static int vidioc_g_parm(struct file *filp, void *priv,
464*4882a593Smuzhiyun struct v4l2_streamparm *parm)
465*4882a593Smuzhiyun {
466*4882a593Smuzhiyun struct go7007 *go = video_drvdata(filp);
467*4882a593Smuzhiyun struct v4l2_fract timeperframe = {
468*4882a593Smuzhiyun .numerator = 1001 * go->fps_scale,
469*4882a593Smuzhiyun .denominator = go->sensor_framerate,
470*4882a593Smuzhiyun };
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
473*4882a593Smuzhiyun return -EINVAL;
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun parm->parm.capture.readbuffers = 2;
476*4882a593Smuzhiyun parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
477*4882a593Smuzhiyun parm->parm.capture.timeperframe = timeperframe;
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun return 0;
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun
vidioc_s_parm(struct file * filp,void * priv,struct v4l2_streamparm * parm)482*4882a593Smuzhiyun static int vidioc_s_parm(struct file *filp, void *priv,
483*4882a593Smuzhiyun struct v4l2_streamparm *parm)
484*4882a593Smuzhiyun {
485*4882a593Smuzhiyun struct go7007 *go = video_drvdata(filp);
486*4882a593Smuzhiyun unsigned int n, d;
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
489*4882a593Smuzhiyun return -EINVAL;
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun n = go->sensor_framerate *
492*4882a593Smuzhiyun parm->parm.capture.timeperframe.numerator;
493*4882a593Smuzhiyun d = 1001 * parm->parm.capture.timeperframe.denominator;
494*4882a593Smuzhiyun if (n != 0 && d != 0 && n > d)
495*4882a593Smuzhiyun go->fps_scale = (n + d/2) / d;
496*4882a593Smuzhiyun else
497*4882a593Smuzhiyun go->fps_scale = 1;
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun return vidioc_g_parm(filp, priv, parm);
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun /* VIDIOC_ENUMSTD on go7007 were used for enumerating the supported fps and
503*4882a593Smuzhiyun its resolution, when the device is not connected to TV.
504*4882a593Smuzhiyun This is were an API abuse, probably used by the lack of specific IOCTL's to
505*4882a593Smuzhiyun enumerate it, by the time the driver was written.
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun However, since kernel 2.6.19, two new ioctls (VIDIOC_ENUM_FRAMEINTERVALS
508*4882a593Smuzhiyun and VIDIOC_ENUM_FRAMESIZES) were added for this purpose.
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun The two functions below implement the newer ioctls
511*4882a593Smuzhiyun */
vidioc_enum_framesizes(struct file * filp,void * priv,struct v4l2_frmsizeenum * fsize)512*4882a593Smuzhiyun static int vidioc_enum_framesizes(struct file *filp, void *priv,
513*4882a593Smuzhiyun struct v4l2_frmsizeenum *fsize)
514*4882a593Smuzhiyun {
515*4882a593Smuzhiyun struct go7007 *go = video_drvdata(filp);
516*4882a593Smuzhiyun int width, height;
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun if (fsize->index > 2)
519*4882a593Smuzhiyun return -EINVAL;
520*4882a593Smuzhiyun
521*4882a593Smuzhiyun if (!valid_pixelformat(fsize->pixel_format))
522*4882a593Smuzhiyun return -EINVAL;
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun get_resolution(go, &width, &height);
525*4882a593Smuzhiyun fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
526*4882a593Smuzhiyun fsize->discrete.width = (width >> fsize->index) & ~0xf;
527*4882a593Smuzhiyun fsize->discrete.height = (height >> fsize->index) & ~0xf;
528*4882a593Smuzhiyun return 0;
529*4882a593Smuzhiyun }
530*4882a593Smuzhiyun
vidioc_enum_frameintervals(struct file * filp,void * priv,struct v4l2_frmivalenum * fival)531*4882a593Smuzhiyun static int vidioc_enum_frameintervals(struct file *filp, void *priv,
532*4882a593Smuzhiyun struct v4l2_frmivalenum *fival)
533*4882a593Smuzhiyun {
534*4882a593Smuzhiyun struct go7007 *go = video_drvdata(filp);
535*4882a593Smuzhiyun int width, height;
536*4882a593Smuzhiyun int i;
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun if (fival->index > 4)
539*4882a593Smuzhiyun return -EINVAL;
540*4882a593Smuzhiyun
541*4882a593Smuzhiyun if (!valid_pixelformat(fival->pixel_format))
542*4882a593Smuzhiyun return -EINVAL;
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun if (!(go->board_info->sensor_flags & GO7007_SENSOR_SCALING)) {
545*4882a593Smuzhiyun get_resolution(go, &width, &height);
546*4882a593Smuzhiyun for (i = 0; i <= 2; i++)
547*4882a593Smuzhiyun if (fival->width == ((width >> i) & ~0xf) &&
548*4882a593Smuzhiyun fival->height == ((height >> i) & ~0xf))
549*4882a593Smuzhiyun break;
550*4882a593Smuzhiyun if (i > 2)
551*4882a593Smuzhiyun return -EINVAL;
552*4882a593Smuzhiyun }
553*4882a593Smuzhiyun fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
554*4882a593Smuzhiyun fival->discrete.numerator = 1001 * (fival->index + 1);
555*4882a593Smuzhiyun fival->discrete.denominator = go->sensor_framerate;
556*4882a593Smuzhiyun return 0;
557*4882a593Smuzhiyun }
558*4882a593Smuzhiyun
vidioc_g_std(struct file * file,void * priv,v4l2_std_id * std)559*4882a593Smuzhiyun static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std)
560*4882a593Smuzhiyun {
561*4882a593Smuzhiyun struct go7007 *go = video_drvdata(file);
562*4882a593Smuzhiyun
563*4882a593Smuzhiyun *std = go->std;
564*4882a593Smuzhiyun return 0;
565*4882a593Smuzhiyun }
566*4882a593Smuzhiyun
go7007_s_std(struct go7007 * go)567*4882a593Smuzhiyun static int go7007_s_std(struct go7007 *go)
568*4882a593Smuzhiyun {
569*4882a593Smuzhiyun if (go->std & V4L2_STD_625_50) {
570*4882a593Smuzhiyun go->standard = GO7007_STD_PAL;
571*4882a593Smuzhiyun go->sensor_framerate = 25025;
572*4882a593Smuzhiyun } else {
573*4882a593Smuzhiyun go->standard = GO7007_STD_NTSC;
574*4882a593Smuzhiyun go->sensor_framerate = 30000;
575*4882a593Smuzhiyun }
576*4882a593Smuzhiyun
577*4882a593Smuzhiyun call_all(&go->v4l2_dev, video, s_std, go->std);
578*4882a593Smuzhiyun set_capture_size(go, NULL, 0);
579*4882a593Smuzhiyun return 0;
580*4882a593Smuzhiyun }
581*4882a593Smuzhiyun
vidioc_s_std(struct file * file,void * priv,v4l2_std_id std)582*4882a593Smuzhiyun static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id std)
583*4882a593Smuzhiyun {
584*4882a593Smuzhiyun struct go7007 *go = video_drvdata(file);
585*4882a593Smuzhiyun
586*4882a593Smuzhiyun if (vb2_is_busy(&go->vidq))
587*4882a593Smuzhiyun return -EBUSY;
588*4882a593Smuzhiyun
589*4882a593Smuzhiyun go->std = std;
590*4882a593Smuzhiyun
591*4882a593Smuzhiyun return go7007_s_std(go);
592*4882a593Smuzhiyun }
593*4882a593Smuzhiyun
vidioc_querystd(struct file * file,void * priv,v4l2_std_id * std)594*4882a593Smuzhiyun static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *std)
595*4882a593Smuzhiyun {
596*4882a593Smuzhiyun struct go7007 *go = video_drvdata(file);
597*4882a593Smuzhiyun
598*4882a593Smuzhiyun return call_all(&go->v4l2_dev, video, querystd, std);
599*4882a593Smuzhiyun }
600*4882a593Smuzhiyun
vidioc_enum_input(struct file * file,void * priv,struct v4l2_input * inp)601*4882a593Smuzhiyun static int vidioc_enum_input(struct file *file, void *priv,
602*4882a593Smuzhiyun struct v4l2_input *inp)
603*4882a593Smuzhiyun {
604*4882a593Smuzhiyun struct go7007 *go = video_drvdata(file);
605*4882a593Smuzhiyun
606*4882a593Smuzhiyun if (inp->index >= go->board_info->num_inputs)
607*4882a593Smuzhiyun return -EINVAL;
608*4882a593Smuzhiyun
609*4882a593Smuzhiyun strscpy(inp->name, go->board_info->inputs[inp->index].name,
610*4882a593Smuzhiyun sizeof(inp->name));
611*4882a593Smuzhiyun
612*4882a593Smuzhiyun /* If this board has a tuner, it will be the first input */
613*4882a593Smuzhiyun if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) &&
614*4882a593Smuzhiyun inp->index == 0)
615*4882a593Smuzhiyun inp->type = V4L2_INPUT_TYPE_TUNER;
616*4882a593Smuzhiyun else
617*4882a593Smuzhiyun inp->type = V4L2_INPUT_TYPE_CAMERA;
618*4882a593Smuzhiyun
619*4882a593Smuzhiyun if (go->board_info->num_aud_inputs)
620*4882a593Smuzhiyun inp->audioset = (1 << go->board_info->num_aud_inputs) - 1;
621*4882a593Smuzhiyun else
622*4882a593Smuzhiyun inp->audioset = 0;
623*4882a593Smuzhiyun inp->tuner = 0;
624*4882a593Smuzhiyun if (go->board_info->sensor_flags & GO7007_SENSOR_TV)
625*4882a593Smuzhiyun inp->std = video_devdata(file)->tvnorms;
626*4882a593Smuzhiyun else
627*4882a593Smuzhiyun inp->std = 0;
628*4882a593Smuzhiyun
629*4882a593Smuzhiyun return 0;
630*4882a593Smuzhiyun }
631*4882a593Smuzhiyun
632*4882a593Smuzhiyun
vidioc_g_input(struct file * file,void * priv,unsigned int * input)633*4882a593Smuzhiyun static int vidioc_g_input(struct file *file, void *priv, unsigned int *input)
634*4882a593Smuzhiyun {
635*4882a593Smuzhiyun struct go7007 *go = video_drvdata(file);
636*4882a593Smuzhiyun
637*4882a593Smuzhiyun *input = go->input;
638*4882a593Smuzhiyun
639*4882a593Smuzhiyun return 0;
640*4882a593Smuzhiyun }
641*4882a593Smuzhiyun
vidioc_enumaudio(struct file * file,void * fh,struct v4l2_audio * a)642*4882a593Smuzhiyun static int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *a)
643*4882a593Smuzhiyun {
644*4882a593Smuzhiyun struct go7007 *go = video_drvdata(file);
645*4882a593Smuzhiyun
646*4882a593Smuzhiyun if (a->index >= go->board_info->num_aud_inputs)
647*4882a593Smuzhiyun return -EINVAL;
648*4882a593Smuzhiyun strscpy(a->name, go->board_info->aud_inputs[a->index].name,
649*4882a593Smuzhiyun sizeof(a->name));
650*4882a593Smuzhiyun a->capability = V4L2_AUDCAP_STEREO;
651*4882a593Smuzhiyun return 0;
652*4882a593Smuzhiyun }
653*4882a593Smuzhiyun
vidioc_g_audio(struct file * file,void * fh,struct v4l2_audio * a)654*4882a593Smuzhiyun static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a)
655*4882a593Smuzhiyun {
656*4882a593Smuzhiyun struct go7007 *go = video_drvdata(file);
657*4882a593Smuzhiyun
658*4882a593Smuzhiyun a->index = go->aud_input;
659*4882a593Smuzhiyun strscpy(a->name, go->board_info->aud_inputs[go->aud_input].name,
660*4882a593Smuzhiyun sizeof(a->name));
661*4882a593Smuzhiyun a->capability = V4L2_AUDCAP_STEREO;
662*4882a593Smuzhiyun return 0;
663*4882a593Smuzhiyun }
664*4882a593Smuzhiyun
vidioc_s_audio(struct file * file,void * fh,const struct v4l2_audio * a)665*4882a593Smuzhiyun static int vidioc_s_audio(struct file *file, void *fh,
666*4882a593Smuzhiyun const struct v4l2_audio *a)
667*4882a593Smuzhiyun {
668*4882a593Smuzhiyun struct go7007 *go = video_drvdata(file);
669*4882a593Smuzhiyun
670*4882a593Smuzhiyun if (a->index >= go->board_info->num_aud_inputs)
671*4882a593Smuzhiyun return -EINVAL;
672*4882a593Smuzhiyun go->aud_input = a->index;
673*4882a593Smuzhiyun v4l2_subdev_call(go->sd_audio, audio, s_routing,
674*4882a593Smuzhiyun go->board_info->aud_inputs[go->aud_input].audio_input, 0, 0);
675*4882a593Smuzhiyun return 0;
676*4882a593Smuzhiyun }
677*4882a593Smuzhiyun
go7007_s_input(struct go7007 * go)678*4882a593Smuzhiyun static void go7007_s_input(struct go7007 *go)
679*4882a593Smuzhiyun {
680*4882a593Smuzhiyun unsigned int input = go->input;
681*4882a593Smuzhiyun
682*4882a593Smuzhiyun v4l2_subdev_call(go->sd_video, video, s_routing,
683*4882a593Smuzhiyun go->board_info->inputs[input].video_input, 0,
684*4882a593Smuzhiyun go->board_info->video_config);
685*4882a593Smuzhiyun if (go->board_info->num_aud_inputs) {
686*4882a593Smuzhiyun int aud_input = go->board_info->inputs[input].audio_index;
687*4882a593Smuzhiyun
688*4882a593Smuzhiyun v4l2_subdev_call(go->sd_audio, audio, s_routing,
689*4882a593Smuzhiyun go->board_info->aud_inputs[aud_input].audio_input, 0, 0);
690*4882a593Smuzhiyun go->aud_input = aud_input;
691*4882a593Smuzhiyun }
692*4882a593Smuzhiyun }
693*4882a593Smuzhiyun
vidioc_s_input(struct file * file,void * priv,unsigned int input)694*4882a593Smuzhiyun static int vidioc_s_input(struct file *file, void *priv, unsigned int input)
695*4882a593Smuzhiyun {
696*4882a593Smuzhiyun struct go7007 *go = video_drvdata(file);
697*4882a593Smuzhiyun
698*4882a593Smuzhiyun if (input >= go->board_info->num_inputs)
699*4882a593Smuzhiyun return -EINVAL;
700*4882a593Smuzhiyun if (vb2_is_busy(&go->vidq))
701*4882a593Smuzhiyun return -EBUSY;
702*4882a593Smuzhiyun
703*4882a593Smuzhiyun go->input = input;
704*4882a593Smuzhiyun go7007_s_input(go);
705*4882a593Smuzhiyun
706*4882a593Smuzhiyun return 0;
707*4882a593Smuzhiyun }
708*4882a593Smuzhiyun
vidioc_g_tuner(struct file * file,void * priv,struct v4l2_tuner * t)709*4882a593Smuzhiyun static int vidioc_g_tuner(struct file *file, void *priv,
710*4882a593Smuzhiyun struct v4l2_tuner *t)
711*4882a593Smuzhiyun {
712*4882a593Smuzhiyun struct go7007 *go = video_drvdata(file);
713*4882a593Smuzhiyun
714*4882a593Smuzhiyun if (t->index != 0)
715*4882a593Smuzhiyun return -EINVAL;
716*4882a593Smuzhiyun
717*4882a593Smuzhiyun strscpy(t->name, "Tuner", sizeof(t->name));
718*4882a593Smuzhiyun return call_all(&go->v4l2_dev, tuner, g_tuner, t);
719*4882a593Smuzhiyun }
720*4882a593Smuzhiyun
vidioc_s_tuner(struct file * file,void * priv,const struct v4l2_tuner * t)721*4882a593Smuzhiyun static int vidioc_s_tuner(struct file *file, void *priv,
722*4882a593Smuzhiyun const struct v4l2_tuner *t)
723*4882a593Smuzhiyun {
724*4882a593Smuzhiyun struct go7007 *go = video_drvdata(file);
725*4882a593Smuzhiyun
726*4882a593Smuzhiyun if (t->index != 0)
727*4882a593Smuzhiyun return -EINVAL;
728*4882a593Smuzhiyun
729*4882a593Smuzhiyun return call_all(&go->v4l2_dev, tuner, s_tuner, t);
730*4882a593Smuzhiyun }
731*4882a593Smuzhiyun
vidioc_g_frequency(struct file * file,void * priv,struct v4l2_frequency * f)732*4882a593Smuzhiyun static int vidioc_g_frequency(struct file *file, void *priv,
733*4882a593Smuzhiyun struct v4l2_frequency *f)
734*4882a593Smuzhiyun {
735*4882a593Smuzhiyun struct go7007 *go = video_drvdata(file);
736*4882a593Smuzhiyun
737*4882a593Smuzhiyun if (f->tuner)
738*4882a593Smuzhiyun return -EINVAL;
739*4882a593Smuzhiyun
740*4882a593Smuzhiyun return call_all(&go->v4l2_dev, tuner, g_frequency, f);
741*4882a593Smuzhiyun }
742*4882a593Smuzhiyun
vidioc_s_frequency(struct file * file,void * priv,const struct v4l2_frequency * f)743*4882a593Smuzhiyun static int vidioc_s_frequency(struct file *file, void *priv,
744*4882a593Smuzhiyun const struct v4l2_frequency *f)
745*4882a593Smuzhiyun {
746*4882a593Smuzhiyun struct go7007 *go = video_drvdata(file);
747*4882a593Smuzhiyun
748*4882a593Smuzhiyun if (f->tuner)
749*4882a593Smuzhiyun return -EINVAL;
750*4882a593Smuzhiyun
751*4882a593Smuzhiyun return call_all(&go->v4l2_dev, tuner, s_frequency, f);
752*4882a593Smuzhiyun }
753*4882a593Smuzhiyun
vidioc_log_status(struct file * file,void * priv)754*4882a593Smuzhiyun static int vidioc_log_status(struct file *file, void *priv)
755*4882a593Smuzhiyun {
756*4882a593Smuzhiyun struct go7007 *go = video_drvdata(file);
757*4882a593Smuzhiyun
758*4882a593Smuzhiyun v4l2_ctrl_log_status(file, priv);
759*4882a593Smuzhiyun return call_all(&go->v4l2_dev, core, log_status);
760*4882a593Smuzhiyun }
761*4882a593Smuzhiyun
vidioc_subscribe_event(struct v4l2_fh * fh,const struct v4l2_event_subscription * sub)762*4882a593Smuzhiyun static int vidioc_subscribe_event(struct v4l2_fh *fh,
763*4882a593Smuzhiyun const struct v4l2_event_subscription *sub)
764*4882a593Smuzhiyun {
765*4882a593Smuzhiyun
766*4882a593Smuzhiyun switch (sub->type) {
767*4882a593Smuzhiyun case V4L2_EVENT_MOTION_DET:
768*4882a593Smuzhiyun /* Allow for up to 30 events (1 second for NTSC) to be
769*4882a593Smuzhiyun * stored. */
770*4882a593Smuzhiyun return v4l2_event_subscribe(fh, sub, 30, NULL);
771*4882a593Smuzhiyun default:
772*4882a593Smuzhiyun return v4l2_ctrl_subscribe_event(fh, sub);
773*4882a593Smuzhiyun }
774*4882a593Smuzhiyun }
775*4882a593Smuzhiyun
776*4882a593Smuzhiyun
go7007_s_ctrl(struct v4l2_ctrl * ctrl)777*4882a593Smuzhiyun static int go7007_s_ctrl(struct v4l2_ctrl *ctrl)
778*4882a593Smuzhiyun {
779*4882a593Smuzhiyun struct go7007 *go =
780*4882a593Smuzhiyun container_of(ctrl->handler, struct go7007, hdl);
781*4882a593Smuzhiyun unsigned y;
782*4882a593Smuzhiyun u8 *mt;
783*4882a593Smuzhiyun
784*4882a593Smuzhiyun switch (ctrl->id) {
785*4882a593Smuzhiyun case V4L2_CID_PIXEL_THRESHOLD0:
786*4882a593Smuzhiyun go->modet[0].pixel_threshold = ctrl->val;
787*4882a593Smuzhiyun break;
788*4882a593Smuzhiyun case V4L2_CID_MOTION_THRESHOLD0:
789*4882a593Smuzhiyun go->modet[0].motion_threshold = ctrl->val;
790*4882a593Smuzhiyun break;
791*4882a593Smuzhiyun case V4L2_CID_MB_THRESHOLD0:
792*4882a593Smuzhiyun go->modet[0].mb_threshold = ctrl->val;
793*4882a593Smuzhiyun break;
794*4882a593Smuzhiyun case V4L2_CID_PIXEL_THRESHOLD1:
795*4882a593Smuzhiyun go->modet[1].pixel_threshold = ctrl->val;
796*4882a593Smuzhiyun break;
797*4882a593Smuzhiyun case V4L2_CID_MOTION_THRESHOLD1:
798*4882a593Smuzhiyun go->modet[1].motion_threshold = ctrl->val;
799*4882a593Smuzhiyun break;
800*4882a593Smuzhiyun case V4L2_CID_MB_THRESHOLD1:
801*4882a593Smuzhiyun go->modet[1].mb_threshold = ctrl->val;
802*4882a593Smuzhiyun break;
803*4882a593Smuzhiyun case V4L2_CID_PIXEL_THRESHOLD2:
804*4882a593Smuzhiyun go->modet[2].pixel_threshold = ctrl->val;
805*4882a593Smuzhiyun break;
806*4882a593Smuzhiyun case V4L2_CID_MOTION_THRESHOLD2:
807*4882a593Smuzhiyun go->modet[2].motion_threshold = ctrl->val;
808*4882a593Smuzhiyun break;
809*4882a593Smuzhiyun case V4L2_CID_MB_THRESHOLD2:
810*4882a593Smuzhiyun go->modet[2].mb_threshold = ctrl->val;
811*4882a593Smuzhiyun break;
812*4882a593Smuzhiyun case V4L2_CID_PIXEL_THRESHOLD3:
813*4882a593Smuzhiyun go->modet[3].pixel_threshold = ctrl->val;
814*4882a593Smuzhiyun break;
815*4882a593Smuzhiyun case V4L2_CID_MOTION_THRESHOLD3:
816*4882a593Smuzhiyun go->modet[3].motion_threshold = ctrl->val;
817*4882a593Smuzhiyun break;
818*4882a593Smuzhiyun case V4L2_CID_MB_THRESHOLD3:
819*4882a593Smuzhiyun go->modet[3].mb_threshold = ctrl->val;
820*4882a593Smuzhiyun break;
821*4882a593Smuzhiyun case V4L2_CID_DETECT_MD_REGION_GRID:
822*4882a593Smuzhiyun mt = go->modet_map;
823*4882a593Smuzhiyun for (y = 0; y < go->height / 16; y++, mt += go->width / 16)
824*4882a593Smuzhiyun memcpy(mt, ctrl->p_new.p_u8 + y * (720 / 16), go->width / 16);
825*4882a593Smuzhiyun break;
826*4882a593Smuzhiyun default:
827*4882a593Smuzhiyun return -EINVAL;
828*4882a593Smuzhiyun }
829*4882a593Smuzhiyun return 0;
830*4882a593Smuzhiyun }
831*4882a593Smuzhiyun
832*4882a593Smuzhiyun static const struct v4l2_file_operations go7007_fops = {
833*4882a593Smuzhiyun .owner = THIS_MODULE,
834*4882a593Smuzhiyun .open = v4l2_fh_open,
835*4882a593Smuzhiyun .release = vb2_fop_release,
836*4882a593Smuzhiyun .unlocked_ioctl = video_ioctl2,
837*4882a593Smuzhiyun .read = vb2_fop_read,
838*4882a593Smuzhiyun .mmap = vb2_fop_mmap,
839*4882a593Smuzhiyun .poll = vb2_fop_poll,
840*4882a593Smuzhiyun };
841*4882a593Smuzhiyun
842*4882a593Smuzhiyun static const struct v4l2_ioctl_ops video_ioctl_ops = {
843*4882a593Smuzhiyun .vidioc_querycap = vidioc_querycap,
844*4882a593Smuzhiyun .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
845*4882a593Smuzhiyun .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
846*4882a593Smuzhiyun .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
847*4882a593Smuzhiyun .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
848*4882a593Smuzhiyun .vidioc_reqbufs = vb2_ioctl_reqbufs,
849*4882a593Smuzhiyun .vidioc_querybuf = vb2_ioctl_querybuf,
850*4882a593Smuzhiyun .vidioc_qbuf = vb2_ioctl_qbuf,
851*4882a593Smuzhiyun .vidioc_dqbuf = vb2_ioctl_dqbuf,
852*4882a593Smuzhiyun .vidioc_g_std = vidioc_g_std,
853*4882a593Smuzhiyun .vidioc_s_std = vidioc_s_std,
854*4882a593Smuzhiyun .vidioc_querystd = vidioc_querystd,
855*4882a593Smuzhiyun .vidioc_enum_input = vidioc_enum_input,
856*4882a593Smuzhiyun .vidioc_g_input = vidioc_g_input,
857*4882a593Smuzhiyun .vidioc_s_input = vidioc_s_input,
858*4882a593Smuzhiyun .vidioc_enumaudio = vidioc_enumaudio,
859*4882a593Smuzhiyun .vidioc_g_audio = vidioc_g_audio,
860*4882a593Smuzhiyun .vidioc_s_audio = vidioc_s_audio,
861*4882a593Smuzhiyun .vidioc_streamon = vb2_ioctl_streamon,
862*4882a593Smuzhiyun .vidioc_streamoff = vb2_ioctl_streamoff,
863*4882a593Smuzhiyun .vidioc_g_tuner = vidioc_g_tuner,
864*4882a593Smuzhiyun .vidioc_s_tuner = vidioc_s_tuner,
865*4882a593Smuzhiyun .vidioc_g_frequency = vidioc_g_frequency,
866*4882a593Smuzhiyun .vidioc_s_frequency = vidioc_s_frequency,
867*4882a593Smuzhiyun .vidioc_g_parm = vidioc_g_parm,
868*4882a593Smuzhiyun .vidioc_s_parm = vidioc_s_parm,
869*4882a593Smuzhiyun .vidioc_enum_framesizes = vidioc_enum_framesizes,
870*4882a593Smuzhiyun .vidioc_enum_frameintervals = vidioc_enum_frameintervals,
871*4882a593Smuzhiyun .vidioc_log_status = vidioc_log_status,
872*4882a593Smuzhiyun .vidioc_subscribe_event = vidioc_subscribe_event,
873*4882a593Smuzhiyun .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
874*4882a593Smuzhiyun };
875*4882a593Smuzhiyun
876*4882a593Smuzhiyun static const struct video_device go7007_template = {
877*4882a593Smuzhiyun .name = "go7007",
878*4882a593Smuzhiyun .fops = &go7007_fops,
879*4882a593Smuzhiyun .release = video_device_release_empty,
880*4882a593Smuzhiyun .ioctl_ops = &video_ioctl_ops,
881*4882a593Smuzhiyun .tvnorms = V4L2_STD_ALL,
882*4882a593Smuzhiyun };
883*4882a593Smuzhiyun
884*4882a593Smuzhiyun static const struct v4l2_ctrl_ops go7007_ctrl_ops = {
885*4882a593Smuzhiyun .s_ctrl = go7007_s_ctrl,
886*4882a593Smuzhiyun };
887*4882a593Smuzhiyun
888*4882a593Smuzhiyun static const struct v4l2_ctrl_config go7007_pixel_threshold0_ctrl = {
889*4882a593Smuzhiyun .ops = &go7007_ctrl_ops,
890*4882a593Smuzhiyun .id = V4L2_CID_PIXEL_THRESHOLD0,
891*4882a593Smuzhiyun .name = "Pixel Threshold Region 0",
892*4882a593Smuzhiyun .type = V4L2_CTRL_TYPE_INTEGER,
893*4882a593Smuzhiyun .def = 20,
894*4882a593Smuzhiyun .max = 32767,
895*4882a593Smuzhiyun .step = 1,
896*4882a593Smuzhiyun };
897*4882a593Smuzhiyun
898*4882a593Smuzhiyun static const struct v4l2_ctrl_config go7007_motion_threshold0_ctrl = {
899*4882a593Smuzhiyun .ops = &go7007_ctrl_ops,
900*4882a593Smuzhiyun .id = V4L2_CID_MOTION_THRESHOLD0,
901*4882a593Smuzhiyun .name = "Motion Threshold Region 0",
902*4882a593Smuzhiyun .type = V4L2_CTRL_TYPE_INTEGER,
903*4882a593Smuzhiyun .def = 80,
904*4882a593Smuzhiyun .max = 32767,
905*4882a593Smuzhiyun .step = 1,
906*4882a593Smuzhiyun };
907*4882a593Smuzhiyun
908*4882a593Smuzhiyun static const struct v4l2_ctrl_config go7007_mb_threshold0_ctrl = {
909*4882a593Smuzhiyun .ops = &go7007_ctrl_ops,
910*4882a593Smuzhiyun .id = V4L2_CID_MB_THRESHOLD0,
911*4882a593Smuzhiyun .name = "MB Threshold Region 0",
912*4882a593Smuzhiyun .type = V4L2_CTRL_TYPE_INTEGER,
913*4882a593Smuzhiyun .def = 200,
914*4882a593Smuzhiyun .max = 32767,
915*4882a593Smuzhiyun .step = 1,
916*4882a593Smuzhiyun };
917*4882a593Smuzhiyun
918*4882a593Smuzhiyun static const struct v4l2_ctrl_config go7007_pixel_threshold1_ctrl = {
919*4882a593Smuzhiyun .ops = &go7007_ctrl_ops,
920*4882a593Smuzhiyun .id = V4L2_CID_PIXEL_THRESHOLD1,
921*4882a593Smuzhiyun .name = "Pixel Threshold Region 1",
922*4882a593Smuzhiyun .type = V4L2_CTRL_TYPE_INTEGER,
923*4882a593Smuzhiyun .def = 20,
924*4882a593Smuzhiyun .max = 32767,
925*4882a593Smuzhiyun .step = 1,
926*4882a593Smuzhiyun };
927*4882a593Smuzhiyun
928*4882a593Smuzhiyun static const struct v4l2_ctrl_config go7007_motion_threshold1_ctrl = {
929*4882a593Smuzhiyun .ops = &go7007_ctrl_ops,
930*4882a593Smuzhiyun .id = V4L2_CID_MOTION_THRESHOLD1,
931*4882a593Smuzhiyun .name = "Motion Threshold Region 1",
932*4882a593Smuzhiyun .type = V4L2_CTRL_TYPE_INTEGER,
933*4882a593Smuzhiyun .def = 80,
934*4882a593Smuzhiyun .max = 32767,
935*4882a593Smuzhiyun .step = 1,
936*4882a593Smuzhiyun };
937*4882a593Smuzhiyun
938*4882a593Smuzhiyun static const struct v4l2_ctrl_config go7007_mb_threshold1_ctrl = {
939*4882a593Smuzhiyun .ops = &go7007_ctrl_ops,
940*4882a593Smuzhiyun .id = V4L2_CID_MB_THRESHOLD1,
941*4882a593Smuzhiyun .name = "MB Threshold Region 1",
942*4882a593Smuzhiyun .type = V4L2_CTRL_TYPE_INTEGER,
943*4882a593Smuzhiyun .def = 200,
944*4882a593Smuzhiyun .max = 32767,
945*4882a593Smuzhiyun .step = 1,
946*4882a593Smuzhiyun };
947*4882a593Smuzhiyun
948*4882a593Smuzhiyun static const struct v4l2_ctrl_config go7007_pixel_threshold2_ctrl = {
949*4882a593Smuzhiyun .ops = &go7007_ctrl_ops,
950*4882a593Smuzhiyun .id = V4L2_CID_PIXEL_THRESHOLD2,
951*4882a593Smuzhiyun .name = "Pixel Threshold Region 2",
952*4882a593Smuzhiyun .type = V4L2_CTRL_TYPE_INTEGER,
953*4882a593Smuzhiyun .def = 20,
954*4882a593Smuzhiyun .max = 32767,
955*4882a593Smuzhiyun .step = 1,
956*4882a593Smuzhiyun };
957*4882a593Smuzhiyun
958*4882a593Smuzhiyun static const struct v4l2_ctrl_config go7007_motion_threshold2_ctrl = {
959*4882a593Smuzhiyun .ops = &go7007_ctrl_ops,
960*4882a593Smuzhiyun .id = V4L2_CID_MOTION_THRESHOLD2,
961*4882a593Smuzhiyun .name = "Motion Threshold Region 2",
962*4882a593Smuzhiyun .type = V4L2_CTRL_TYPE_INTEGER,
963*4882a593Smuzhiyun .def = 80,
964*4882a593Smuzhiyun .max = 32767,
965*4882a593Smuzhiyun .step = 1,
966*4882a593Smuzhiyun };
967*4882a593Smuzhiyun
968*4882a593Smuzhiyun static const struct v4l2_ctrl_config go7007_mb_threshold2_ctrl = {
969*4882a593Smuzhiyun .ops = &go7007_ctrl_ops,
970*4882a593Smuzhiyun .id = V4L2_CID_MB_THRESHOLD2,
971*4882a593Smuzhiyun .name = "MB Threshold Region 2",
972*4882a593Smuzhiyun .type = V4L2_CTRL_TYPE_INTEGER,
973*4882a593Smuzhiyun .def = 200,
974*4882a593Smuzhiyun .max = 32767,
975*4882a593Smuzhiyun .step = 1,
976*4882a593Smuzhiyun };
977*4882a593Smuzhiyun
978*4882a593Smuzhiyun static const struct v4l2_ctrl_config go7007_pixel_threshold3_ctrl = {
979*4882a593Smuzhiyun .ops = &go7007_ctrl_ops,
980*4882a593Smuzhiyun .id = V4L2_CID_PIXEL_THRESHOLD3,
981*4882a593Smuzhiyun .name = "Pixel Threshold Region 3",
982*4882a593Smuzhiyun .type = V4L2_CTRL_TYPE_INTEGER,
983*4882a593Smuzhiyun .def = 20,
984*4882a593Smuzhiyun .max = 32767,
985*4882a593Smuzhiyun .step = 1,
986*4882a593Smuzhiyun };
987*4882a593Smuzhiyun
988*4882a593Smuzhiyun static const struct v4l2_ctrl_config go7007_motion_threshold3_ctrl = {
989*4882a593Smuzhiyun .ops = &go7007_ctrl_ops,
990*4882a593Smuzhiyun .id = V4L2_CID_MOTION_THRESHOLD3,
991*4882a593Smuzhiyun .name = "Motion Threshold Region 3",
992*4882a593Smuzhiyun .type = V4L2_CTRL_TYPE_INTEGER,
993*4882a593Smuzhiyun .def = 80,
994*4882a593Smuzhiyun .max = 32767,
995*4882a593Smuzhiyun .step = 1,
996*4882a593Smuzhiyun };
997*4882a593Smuzhiyun
998*4882a593Smuzhiyun static const struct v4l2_ctrl_config go7007_mb_threshold3_ctrl = {
999*4882a593Smuzhiyun .ops = &go7007_ctrl_ops,
1000*4882a593Smuzhiyun .id = V4L2_CID_MB_THRESHOLD3,
1001*4882a593Smuzhiyun .name = "MB Threshold Region 3",
1002*4882a593Smuzhiyun .type = V4L2_CTRL_TYPE_INTEGER,
1003*4882a593Smuzhiyun .def = 200,
1004*4882a593Smuzhiyun .max = 32767,
1005*4882a593Smuzhiyun .step = 1,
1006*4882a593Smuzhiyun };
1007*4882a593Smuzhiyun
1008*4882a593Smuzhiyun static const struct v4l2_ctrl_config go7007_mb_regions_ctrl = {
1009*4882a593Smuzhiyun .ops = &go7007_ctrl_ops,
1010*4882a593Smuzhiyun .id = V4L2_CID_DETECT_MD_REGION_GRID,
1011*4882a593Smuzhiyun .dims = { 576 / 16, 720 / 16 },
1012*4882a593Smuzhiyun .max = 3,
1013*4882a593Smuzhiyun .step = 1,
1014*4882a593Smuzhiyun };
1015*4882a593Smuzhiyun
go7007_v4l2_ctrl_init(struct go7007 * go)1016*4882a593Smuzhiyun int go7007_v4l2_ctrl_init(struct go7007 *go)
1017*4882a593Smuzhiyun {
1018*4882a593Smuzhiyun struct v4l2_ctrl_handler *hdl = &go->hdl;
1019*4882a593Smuzhiyun struct v4l2_ctrl *ctrl;
1020*4882a593Smuzhiyun
1021*4882a593Smuzhiyun v4l2_ctrl_handler_init(hdl, 22);
1022*4882a593Smuzhiyun go->mpeg_video_gop_size = v4l2_ctrl_new_std(hdl, NULL,
1023*4882a593Smuzhiyun V4L2_CID_MPEG_VIDEO_GOP_SIZE, 0, 34, 1, 15);
1024*4882a593Smuzhiyun go->mpeg_video_gop_closure = v4l2_ctrl_new_std(hdl, NULL,
1025*4882a593Smuzhiyun V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, 0, 1, 1, 1);
1026*4882a593Smuzhiyun go->mpeg_video_bitrate = v4l2_ctrl_new_std(hdl, NULL,
1027*4882a593Smuzhiyun V4L2_CID_MPEG_VIDEO_BITRATE,
1028*4882a593Smuzhiyun 64000, 10000000, 1, 9800000);
1029*4882a593Smuzhiyun go->mpeg_video_b_frames = v4l2_ctrl_new_std(hdl, NULL,
1030*4882a593Smuzhiyun V4L2_CID_MPEG_VIDEO_B_FRAMES, 0, 2, 2, 0);
1031*4882a593Smuzhiyun go->mpeg_video_rep_seqheader = v4l2_ctrl_new_std(hdl, NULL,
1032*4882a593Smuzhiyun V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER, 0, 1, 1, 1);
1033*4882a593Smuzhiyun
1034*4882a593Smuzhiyun go->mpeg_video_aspect_ratio = v4l2_ctrl_new_std_menu(hdl, NULL,
1035*4882a593Smuzhiyun V4L2_CID_MPEG_VIDEO_ASPECT,
1036*4882a593Smuzhiyun V4L2_MPEG_VIDEO_ASPECT_16x9, 0,
1037*4882a593Smuzhiyun V4L2_MPEG_VIDEO_ASPECT_1x1);
1038*4882a593Smuzhiyun ctrl = v4l2_ctrl_new_std(hdl, NULL,
1039*4882a593Smuzhiyun V4L2_CID_JPEG_ACTIVE_MARKER, 0,
1040*4882a593Smuzhiyun V4L2_JPEG_ACTIVE_MARKER_DQT |
1041*4882a593Smuzhiyun V4L2_JPEG_ACTIVE_MARKER_DHT, 0,
1042*4882a593Smuzhiyun V4L2_JPEG_ACTIVE_MARKER_DQT |
1043*4882a593Smuzhiyun V4L2_JPEG_ACTIVE_MARKER_DHT);
1044*4882a593Smuzhiyun if (ctrl)
1045*4882a593Smuzhiyun ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
1046*4882a593Smuzhiyun v4l2_ctrl_new_custom(hdl, &go7007_pixel_threshold0_ctrl, NULL);
1047*4882a593Smuzhiyun v4l2_ctrl_new_custom(hdl, &go7007_motion_threshold0_ctrl, NULL);
1048*4882a593Smuzhiyun v4l2_ctrl_new_custom(hdl, &go7007_mb_threshold0_ctrl, NULL);
1049*4882a593Smuzhiyun v4l2_ctrl_new_custom(hdl, &go7007_pixel_threshold1_ctrl, NULL);
1050*4882a593Smuzhiyun v4l2_ctrl_new_custom(hdl, &go7007_motion_threshold1_ctrl, NULL);
1051*4882a593Smuzhiyun v4l2_ctrl_new_custom(hdl, &go7007_mb_threshold1_ctrl, NULL);
1052*4882a593Smuzhiyun v4l2_ctrl_new_custom(hdl, &go7007_pixel_threshold2_ctrl, NULL);
1053*4882a593Smuzhiyun v4l2_ctrl_new_custom(hdl, &go7007_motion_threshold2_ctrl, NULL);
1054*4882a593Smuzhiyun v4l2_ctrl_new_custom(hdl, &go7007_mb_threshold2_ctrl, NULL);
1055*4882a593Smuzhiyun v4l2_ctrl_new_custom(hdl, &go7007_pixel_threshold3_ctrl, NULL);
1056*4882a593Smuzhiyun v4l2_ctrl_new_custom(hdl, &go7007_motion_threshold3_ctrl, NULL);
1057*4882a593Smuzhiyun v4l2_ctrl_new_custom(hdl, &go7007_mb_threshold3_ctrl, NULL);
1058*4882a593Smuzhiyun v4l2_ctrl_new_custom(hdl, &go7007_mb_regions_ctrl, NULL);
1059*4882a593Smuzhiyun go->modet_mode = v4l2_ctrl_new_std_menu(hdl, NULL,
1060*4882a593Smuzhiyun V4L2_CID_DETECT_MD_MODE,
1061*4882a593Smuzhiyun V4L2_DETECT_MD_MODE_REGION_GRID,
1062*4882a593Smuzhiyun 1 << V4L2_DETECT_MD_MODE_THRESHOLD_GRID,
1063*4882a593Smuzhiyun V4L2_DETECT_MD_MODE_DISABLED);
1064*4882a593Smuzhiyun if (hdl->error) {
1065*4882a593Smuzhiyun int rv = hdl->error;
1066*4882a593Smuzhiyun
1067*4882a593Smuzhiyun v4l2_err(&go->v4l2_dev, "Could not register controls\n");
1068*4882a593Smuzhiyun return rv;
1069*4882a593Smuzhiyun }
1070*4882a593Smuzhiyun go->v4l2_dev.ctrl_handler = hdl;
1071*4882a593Smuzhiyun return 0;
1072*4882a593Smuzhiyun }
1073*4882a593Smuzhiyun
go7007_v4l2_init(struct go7007 * go)1074*4882a593Smuzhiyun int go7007_v4l2_init(struct go7007 *go)
1075*4882a593Smuzhiyun {
1076*4882a593Smuzhiyun struct video_device *vdev = &go->vdev;
1077*4882a593Smuzhiyun int rv;
1078*4882a593Smuzhiyun
1079*4882a593Smuzhiyun mutex_init(&go->serialize_lock);
1080*4882a593Smuzhiyun mutex_init(&go->queue_lock);
1081*4882a593Smuzhiyun
1082*4882a593Smuzhiyun INIT_LIST_HEAD(&go->vidq_active);
1083*4882a593Smuzhiyun go->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1084*4882a593Smuzhiyun go->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
1085*4882a593Smuzhiyun go->vidq.ops = &go7007_video_qops;
1086*4882a593Smuzhiyun go->vidq.mem_ops = &vb2_vmalloc_memops;
1087*4882a593Smuzhiyun go->vidq.drv_priv = go;
1088*4882a593Smuzhiyun go->vidq.buf_struct_size = sizeof(struct go7007_buffer);
1089*4882a593Smuzhiyun go->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
1090*4882a593Smuzhiyun go->vidq.lock = &go->queue_lock;
1091*4882a593Smuzhiyun rv = vb2_queue_init(&go->vidq);
1092*4882a593Smuzhiyun if (rv)
1093*4882a593Smuzhiyun return rv;
1094*4882a593Smuzhiyun *vdev = go7007_template;
1095*4882a593Smuzhiyun vdev->lock = &go->serialize_lock;
1096*4882a593Smuzhiyun vdev->queue = &go->vidq;
1097*4882a593Smuzhiyun vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
1098*4882a593Smuzhiyun V4L2_CAP_STREAMING;
1099*4882a593Smuzhiyun if (go->board_info->num_aud_inputs)
1100*4882a593Smuzhiyun vdev->device_caps |= V4L2_CAP_AUDIO;
1101*4882a593Smuzhiyun if (go->board_info->flags & GO7007_BOARD_HAS_TUNER)
1102*4882a593Smuzhiyun vdev->device_caps |= V4L2_CAP_TUNER;
1103*4882a593Smuzhiyun video_set_drvdata(vdev, go);
1104*4882a593Smuzhiyun vdev->v4l2_dev = &go->v4l2_dev;
1105*4882a593Smuzhiyun if (!v4l2_device_has_op(&go->v4l2_dev, 0, video, querystd))
1106*4882a593Smuzhiyun v4l2_disable_ioctl(vdev, VIDIOC_QUERYSTD);
1107*4882a593Smuzhiyun if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER)) {
1108*4882a593Smuzhiyun v4l2_disable_ioctl(vdev, VIDIOC_S_FREQUENCY);
1109*4882a593Smuzhiyun v4l2_disable_ioctl(vdev, VIDIOC_G_FREQUENCY);
1110*4882a593Smuzhiyun v4l2_disable_ioctl(vdev, VIDIOC_S_TUNER);
1111*4882a593Smuzhiyun v4l2_disable_ioctl(vdev, VIDIOC_G_TUNER);
1112*4882a593Smuzhiyun } else {
1113*4882a593Smuzhiyun struct v4l2_frequency f = {
1114*4882a593Smuzhiyun .type = V4L2_TUNER_ANALOG_TV,
1115*4882a593Smuzhiyun .frequency = 980,
1116*4882a593Smuzhiyun };
1117*4882a593Smuzhiyun
1118*4882a593Smuzhiyun call_all(&go->v4l2_dev, tuner, s_frequency, &f);
1119*4882a593Smuzhiyun }
1120*4882a593Smuzhiyun if (!(go->board_info->sensor_flags & GO7007_SENSOR_TV)) {
1121*4882a593Smuzhiyun v4l2_disable_ioctl(vdev, VIDIOC_G_STD);
1122*4882a593Smuzhiyun v4l2_disable_ioctl(vdev, VIDIOC_S_STD);
1123*4882a593Smuzhiyun vdev->tvnorms = 0;
1124*4882a593Smuzhiyun }
1125*4882a593Smuzhiyun if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING)
1126*4882a593Smuzhiyun v4l2_disable_ioctl(vdev, VIDIOC_ENUM_FRAMESIZES);
1127*4882a593Smuzhiyun if (go->board_info->num_aud_inputs == 0) {
1128*4882a593Smuzhiyun v4l2_disable_ioctl(vdev, VIDIOC_G_AUDIO);
1129*4882a593Smuzhiyun v4l2_disable_ioctl(vdev, VIDIOC_S_AUDIO);
1130*4882a593Smuzhiyun v4l2_disable_ioctl(vdev, VIDIOC_ENUMAUDIO);
1131*4882a593Smuzhiyun }
1132*4882a593Smuzhiyun /* Setup correct crystal frequency on this board */
1133*4882a593Smuzhiyun if (go->board_info->sensor_flags & GO7007_SENSOR_SAA7115)
1134*4882a593Smuzhiyun v4l2_subdev_call(go->sd_video, video, s_crystal_freq,
1135*4882a593Smuzhiyun SAA7115_FREQ_24_576_MHZ,
1136*4882a593Smuzhiyun SAA7115_FREQ_FL_APLL | SAA7115_FREQ_FL_UCGC |
1137*4882a593Smuzhiyun SAA7115_FREQ_FL_DOUBLE_ASCLK);
1138*4882a593Smuzhiyun go7007_s_input(go);
1139*4882a593Smuzhiyun if (go->board_info->sensor_flags & GO7007_SENSOR_TV)
1140*4882a593Smuzhiyun go7007_s_std(go);
1141*4882a593Smuzhiyun rv = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
1142*4882a593Smuzhiyun if (rv < 0)
1143*4882a593Smuzhiyun return rv;
1144*4882a593Smuzhiyun dev_info(go->dev, "registered device %s [v4l2]\n",
1145*4882a593Smuzhiyun video_device_node_name(vdev));
1146*4882a593Smuzhiyun
1147*4882a593Smuzhiyun return 0;
1148*4882a593Smuzhiyun }
1149*4882a593Smuzhiyun
go7007_v4l2_remove(struct go7007 * go)1150*4882a593Smuzhiyun void go7007_v4l2_remove(struct go7007 *go)
1151*4882a593Smuzhiyun {
1152*4882a593Smuzhiyun v4l2_ctrl_handler_free(&go->hdl);
1153*4882a593Smuzhiyun }
1154