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