diff options
Diffstat (limited to 'drivers/staging/media/go7007/go7007-v4l2.c')
-rw-r--r-- | drivers/staging/media/go7007/go7007-v4l2.c | 1839 |
1 files changed, 1839 insertions, 0 deletions
diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c new file mode 100644 index 00000000000..2b27d8da70a --- /dev/null +++ b/drivers/staging/media/go7007/go7007-v4l2.c | |||
@@ -0,0 +1,1839 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005-2006 Micronas USA Inc. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License (Version 2) as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program; if not, write to the Free Software Foundation, | ||
15 | * Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | ||
16 | */ | ||
17 | |||
18 | #include <linux/module.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/version.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/sched.h> | ||
23 | #include <linux/spinlock.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/fs.h> | ||
26 | #include <linux/unistd.h> | ||
27 | #include <linux/time.h> | ||
28 | #include <linux/vmalloc.h> | ||
29 | #include <linux/pagemap.h> | ||
30 | #include <linux/videodev2.h> | ||
31 | #include <media/v4l2-common.h> | ||
32 | #include <media/v4l2-ioctl.h> | ||
33 | #include <media/v4l2-subdev.h> | ||
34 | #include <linux/i2c.h> | ||
35 | #include <linux/mutex.h> | ||
36 | #include <linux/uaccess.h> | ||
37 | #include <asm/system.h> | ||
38 | |||
39 | #include "go7007.h" | ||
40 | #include "go7007-priv.h" | ||
41 | #include "wis-i2c.h" | ||
42 | |||
43 | /* Temporary defines until accepted in v4l-dvb */ | ||
44 | #ifndef V4L2_MPEG_STREAM_TYPE_MPEG_ELEM | ||
45 | #define V4L2_MPEG_STREAM_TYPE_MPEG_ELEM 6 /* MPEG elementary stream */ | ||
46 | #endif | ||
47 | #ifndef V4L2_MPEG_VIDEO_ENCODING_MPEG_4 | ||
48 | #define V4L2_MPEG_VIDEO_ENCODING_MPEG_4 3 | ||
49 | #endif | ||
50 | |||
51 | #define call_all(dev, o, f, args...) \ | ||
52 | v4l2_device_call_until_err(dev, 0, o, f, ##args) | ||
53 | |||
54 | static void deactivate_buffer(struct go7007_buffer *gobuf) | ||
55 | { | ||
56 | int i; | ||
57 | |||
58 | if (gobuf->state != BUF_STATE_IDLE) { | ||
59 | list_del(&gobuf->stream); | ||
60 | gobuf->state = BUF_STATE_IDLE; | ||
61 | } | ||
62 | if (gobuf->page_count > 0) { | ||
63 | for (i = 0; i < gobuf->page_count; ++i) | ||
64 | page_cache_release(gobuf->pages[i]); | ||
65 | gobuf->page_count = 0; | ||
66 | } | ||
67 | } | ||
68 | |||
69 | static void abort_queued(struct go7007 *go) | ||
70 | { | ||
71 | struct go7007_buffer *gobuf, *next; | ||
72 | |||
73 | list_for_each_entry_safe(gobuf, next, &go->stream, stream) { | ||
74 | deactivate_buffer(gobuf); | ||
75 | } | ||
76 | } | ||
77 | |||
78 | static int go7007_streamoff(struct go7007 *go) | ||
79 | { | ||
80 | int retval = -EINVAL; | ||
81 | unsigned long flags; | ||
82 | |||
83 | mutex_lock(&go->hw_lock); | ||
84 | if (go->streaming) { | ||
85 | go->streaming = 0; | ||
86 | go7007_stream_stop(go); | ||
87 | spin_lock_irqsave(&go->spinlock, flags); | ||
88 | abort_queued(go); | ||
89 | spin_unlock_irqrestore(&go->spinlock, flags); | ||
90 | go7007_reset_encoder(go); | ||
91 | retval = 0; | ||
92 | } | ||
93 | mutex_unlock(&go->hw_lock); | ||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | static int go7007_open(struct file *file) | ||
98 | { | ||
99 | struct go7007 *go = video_get_drvdata(video_devdata(file)); | ||
100 | struct go7007_file *gofh; | ||
101 | |||
102 | if (go->status != STATUS_ONLINE) | ||
103 | return -EBUSY; | ||
104 | gofh = kmalloc(sizeof(struct go7007_file), GFP_KERNEL); | ||
105 | if (gofh == NULL) | ||
106 | return -ENOMEM; | ||
107 | ++go->ref_count; | ||
108 | gofh->go = go; | ||
109 | mutex_init(&gofh->lock); | ||
110 | gofh->buf_count = 0; | ||
111 | file->private_data = gofh; | ||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | static int go7007_release(struct file *file) | ||
116 | { | ||
117 | struct go7007_file *gofh = file->private_data; | ||
118 | struct go7007 *go = gofh->go; | ||
119 | |||
120 | if (gofh->buf_count > 0) { | ||
121 | go7007_streamoff(go); | ||
122 | go->in_use = 0; | ||
123 | kfree(gofh->bufs); | ||
124 | gofh->buf_count = 0; | ||
125 | } | ||
126 | kfree(gofh); | ||
127 | if (--go->ref_count == 0) | ||
128 | kfree(go); | ||
129 | file->private_data = NULL; | ||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | static u32 get_frame_type_flag(struct go7007_buffer *gobuf, int format) | ||
134 | { | ||
135 | u8 *f = page_address(gobuf->pages[0]); | ||
136 | |||
137 | switch (format) { | ||
138 | case GO7007_FORMAT_MJPEG: | ||
139 | return V4L2_BUF_FLAG_KEYFRAME; | ||
140 | case GO7007_FORMAT_MPEG4: | ||
141 | switch ((f[gobuf->frame_offset + 4] >> 6) & 0x3) { | ||
142 | case 0: | ||
143 | return V4L2_BUF_FLAG_KEYFRAME; | ||
144 | case 1: | ||
145 | return V4L2_BUF_FLAG_PFRAME; | ||
146 | case 2: | ||
147 | return V4L2_BUF_FLAG_BFRAME; | ||
148 | default: | ||
149 | return 0; | ||
150 | } | ||
151 | case GO7007_FORMAT_MPEG1: | ||
152 | case GO7007_FORMAT_MPEG2: | ||
153 | switch ((f[gobuf->frame_offset + 5] >> 3) & 0x7) { | ||
154 | case 1: | ||
155 | return V4L2_BUF_FLAG_KEYFRAME; | ||
156 | case 2: | ||
157 | return V4L2_BUF_FLAG_PFRAME; | ||
158 | case 3: | ||
159 | return V4L2_BUF_FLAG_BFRAME; | ||
160 | default: | ||
161 | return 0; | ||
162 | } | ||
163 | } | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try) | ||
169 | { | ||
170 | int sensor_height = 0, sensor_width = 0; | ||
171 | int width, height, i; | ||
172 | |||
173 | if (fmt != NULL && fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG && | ||
174 | fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MPEG && | ||
175 | fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MPEG4) | ||
176 | return -EINVAL; | ||
177 | |||
178 | switch (go->standard) { | ||
179 | case GO7007_STD_NTSC: | ||
180 | sensor_width = 720; | ||
181 | sensor_height = 480; | ||
182 | break; | ||
183 | case GO7007_STD_PAL: | ||
184 | sensor_width = 720; | ||
185 | sensor_height = 576; | ||
186 | break; | ||
187 | case GO7007_STD_OTHER: | ||
188 | sensor_width = go->board_info->sensor_width; | ||
189 | sensor_height = go->board_info->sensor_height; | ||
190 | break; | ||
191 | } | ||
192 | |||
193 | if (fmt == NULL) { | ||
194 | width = sensor_width; | ||
195 | height = sensor_height; | ||
196 | } else if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING) { | ||
197 | if (fmt->fmt.pix.width > sensor_width) | ||
198 | width = sensor_width; | ||
199 | else if (fmt->fmt.pix.width < 144) | ||
200 | width = 144; | ||
201 | else | ||
202 | width = fmt->fmt.pix.width & ~0x0f; | ||
203 | |||
204 | if (fmt->fmt.pix.height > sensor_height) | ||
205 | height = sensor_height; | ||
206 | else if (fmt->fmt.pix.height < 96) | ||
207 | height = 96; | ||
208 | else | ||
209 | height = fmt->fmt.pix.height & ~0x0f; | ||
210 | } else { | ||
211 | int requested_size = fmt->fmt.pix.width * fmt->fmt.pix.height; | ||
212 | int sensor_size = sensor_width * sensor_height; | ||
213 | |||
214 | if (64 * requested_size < 9 * sensor_size) { | ||
215 | width = sensor_width / 4; | ||
216 | height = sensor_height / 4; | ||
217 | } else if (64 * requested_size < 36 * sensor_size) { | ||
218 | width = sensor_width / 2; | ||
219 | height = sensor_height / 2; | ||
220 | } else { | ||
221 | width = sensor_width; | ||
222 | height = sensor_height; | ||
223 | } | ||
224 | width &= ~0xf; | ||
225 | height &= ~0xf; | ||
226 | } | ||
227 | |||
228 | if (fmt != NULL) { | ||
229 | u32 pixelformat = fmt->fmt.pix.pixelformat; | ||
230 | |||
231 | memset(fmt, 0, sizeof(*fmt)); | ||
232 | fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
233 | fmt->fmt.pix.width = width; | ||
234 | fmt->fmt.pix.height = height; | ||
235 | fmt->fmt.pix.pixelformat = pixelformat; | ||
236 | fmt->fmt.pix.field = V4L2_FIELD_NONE; | ||
237 | fmt->fmt.pix.bytesperline = 0; | ||
238 | fmt->fmt.pix.sizeimage = GO7007_BUF_SIZE; | ||
239 | fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; /* ?? */ | ||
240 | } | ||
241 | |||
242 | if (try) | ||
243 | return 0; | ||
244 | |||
245 | go->width = width; | ||
246 | go->height = height; | ||
247 | go->encoder_h_offset = go->board_info->sensor_h_offset; | ||
248 | go->encoder_v_offset = go->board_info->sensor_v_offset; | ||
249 | for (i = 0; i < 4; ++i) | ||
250 | go->modet[i].enable = 0; | ||
251 | for (i = 0; i < 1624; ++i) | ||
252 | go->modet_map[i] = 0; | ||
253 | |||
254 | if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING) { | ||
255 | struct v4l2_mbus_framefmt mbus_fmt; | ||
256 | |||
257 | mbus_fmt.code = V4L2_MBUS_FMT_FIXED; | ||
258 | if (fmt != NULL) | ||
259 | mbus_fmt.width = fmt->fmt.pix.width; | ||
260 | else | ||
261 | mbus_fmt.width = width; | ||
262 | |||
263 | if (height > sensor_height / 2) { | ||
264 | mbus_fmt.height = height / 2; | ||
265 | go->encoder_v_halve = 0; | ||
266 | } else { | ||
267 | mbus_fmt.height = height; | ||
268 | go->encoder_v_halve = 1; | ||
269 | } | ||
270 | call_all(&go->v4l2_dev, video, s_mbus_fmt, &mbus_fmt); | ||
271 | } else { | ||
272 | if (width <= sensor_width / 4) { | ||
273 | go->encoder_h_halve = 1; | ||
274 | go->encoder_v_halve = 1; | ||
275 | go->encoder_subsample = 1; | ||
276 | } else if (width <= sensor_width / 2) { | ||
277 | go->encoder_h_halve = 1; | ||
278 | go->encoder_v_halve = 1; | ||
279 | go->encoder_subsample = 0; | ||
280 | } else { | ||
281 | go->encoder_h_halve = 0; | ||
282 | go->encoder_v_halve = 0; | ||
283 | go->encoder_subsample = 0; | ||
284 | } | ||
285 | } | ||
286 | |||
287 | if (fmt == NULL) | ||
288 | return 0; | ||
289 | |||
290 | switch (fmt->fmt.pix.pixelformat) { | ||
291 | case V4L2_PIX_FMT_MPEG: | ||
292 | if (go->format == GO7007_FORMAT_MPEG1 || | ||
293 | go->format == GO7007_FORMAT_MPEG2 || | ||
294 | go->format == GO7007_FORMAT_MPEG4) | ||
295 | break; | ||
296 | go->format = GO7007_FORMAT_MPEG1; | ||
297 | go->pali = 0; | ||
298 | go->aspect_ratio = GO7007_RATIO_1_1; | ||
299 | go->gop_size = go->sensor_framerate / 1000; | ||
300 | go->ipb = 0; | ||
301 | go->closed_gop = 1; | ||
302 | go->repeat_seqhead = 1; | ||
303 | go->seq_header_enable = 1; | ||
304 | go->gop_header_enable = 1; | ||
305 | go->dvd_mode = 0; | ||
306 | break; | ||
307 | /* Backwards compatibility only! */ | ||
308 | case V4L2_PIX_FMT_MPEG4: | ||
309 | if (go->format == GO7007_FORMAT_MPEG4) | ||
310 | break; | ||
311 | go->format = GO7007_FORMAT_MPEG4; | ||
312 | go->pali = 0xf5; | ||
313 | go->aspect_ratio = GO7007_RATIO_1_1; | ||
314 | go->gop_size = go->sensor_framerate / 1000; | ||
315 | go->ipb = 0; | ||
316 | go->closed_gop = 1; | ||
317 | go->repeat_seqhead = 1; | ||
318 | go->seq_header_enable = 1; | ||
319 | go->gop_header_enable = 1; | ||
320 | go->dvd_mode = 0; | ||
321 | break; | ||
322 | case V4L2_PIX_FMT_MJPEG: | ||
323 | go->format = GO7007_FORMAT_MJPEG; | ||
324 | go->pali = 0; | ||
325 | go->aspect_ratio = GO7007_RATIO_1_1; | ||
326 | go->gop_size = 0; | ||
327 | go->ipb = 0; | ||
328 | go->closed_gop = 0; | ||
329 | go->repeat_seqhead = 0; | ||
330 | go->seq_header_enable = 0; | ||
331 | go->gop_header_enable = 0; | ||
332 | go->dvd_mode = 0; | ||
333 | break; | ||
334 | } | ||
335 | return 0; | ||
336 | } | ||
337 | |||
338 | #if 0 | ||
339 | static int clip_to_modet_map(struct go7007 *go, int region, | ||
340 | struct v4l2_clip *clip_list) | ||
341 | { | ||
342 | struct v4l2_clip clip, *clip_ptr; | ||
343 | int x, y, mbnum; | ||
344 | |||
345 | /* Check if coordinates are OK and if any macroblocks are already | ||
346 | * used by other regions (besides 0) */ | ||
347 | clip_ptr = clip_list; | ||
348 | while (clip_ptr) { | ||
349 | if (copy_from_user(&clip, clip_ptr, sizeof(clip))) | ||
350 | return -EFAULT; | ||
351 | if (clip.c.left < 0 || (clip.c.left & 0xF) || | ||
352 | clip.c.width <= 0 || (clip.c.width & 0xF)) | ||
353 | return -EINVAL; | ||
354 | if (clip.c.left + clip.c.width > go->width) | ||
355 | return -EINVAL; | ||
356 | if (clip.c.top < 0 || (clip.c.top & 0xF) || | ||
357 | clip.c.height <= 0 || (clip.c.height & 0xF)) | ||
358 | return -EINVAL; | ||
359 | if (clip.c.top + clip.c.height > go->height) | ||
360 | return -EINVAL; | ||
361 | for (y = 0; y < clip.c.height; y += 16) | ||
362 | for (x = 0; x < clip.c.width; x += 16) { | ||
363 | mbnum = (go->width >> 4) * | ||
364 | ((clip.c.top + y) >> 4) + | ||
365 | ((clip.c.left + x) >> 4); | ||
366 | if (go->modet_map[mbnum] != 0 && | ||
367 | go->modet_map[mbnum] != region) | ||
368 | return -EBUSY; | ||
369 | } | ||
370 | clip_ptr = clip.next; | ||
371 | } | ||
372 | |||
373 | /* Clear old region macroblocks */ | ||
374 | for (mbnum = 0; mbnum < 1624; ++mbnum) | ||
375 | if (go->modet_map[mbnum] == region) | ||
376 | go->modet_map[mbnum] = 0; | ||
377 | |||
378 | /* Claim macroblocks in this list */ | ||
379 | clip_ptr = clip_list; | ||
380 | while (clip_ptr) { | ||
381 | if (copy_from_user(&clip, clip_ptr, sizeof(clip))) | ||
382 | return -EFAULT; | ||
383 | for (y = 0; y < clip.c.height; y += 16) | ||
384 | for (x = 0; x < clip.c.width; x += 16) { | ||
385 | mbnum = (go->width >> 4) * | ||
386 | ((clip.c.top + y) >> 4) + | ||
387 | ((clip.c.left + x) >> 4); | ||
388 | go->modet_map[mbnum] = region; | ||
389 | } | ||
390 | clip_ptr = clip.next; | ||
391 | } | ||
392 | return 0; | ||
393 | } | ||
394 | #endif | ||
395 | |||
396 | static int mpeg_query_ctrl(struct v4l2_queryctrl *ctrl) | ||
397 | { | ||
398 | static const u32 mpeg_ctrls[] = { | ||
399 | V4L2_CID_MPEG_CLASS, | ||
400 | V4L2_CID_MPEG_STREAM_TYPE, | ||
401 | V4L2_CID_MPEG_VIDEO_ENCODING, | ||
402 | V4L2_CID_MPEG_VIDEO_ASPECT, | ||
403 | V4L2_CID_MPEG_VIDEO_GOP_SIZE, | ||
404 | V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, | ||
405 | V4L2_CID_MPEG_VIDEO_BITRATE, | ||
406 | 0 | ||
407 | }; | ||
408 | static const u32 *ctrl_classes[] = { | ||
409 | mpeg_ctrls, | ||
410 | NULL | ||
411 | }; | ||
412 | |||
413 | ctrl->id = v4l2_ctrl_next(ctrl_classes, ctrl->id); | ||
414 | |||
415 | switch (ctrl->id) { | ||
416 | case V4L2_CID_MPEG_CLASS: | ||
417 | return v4l2_ctrl_query_fill(ctrl, 0, 0, 0, 0); | ||
418 | case V4L2_CID_MPEG_STREAM_TYPE: | ||
419 | return v4l2_ctrl_query_fill(ctrl, | ||
420 | V4L2_MPEG_STREAM_TYPE_MPEG2_DVD, | ||
421 | V4L2_MPEG_STREAM_TYPE_MPEG_ELEM, 1, | ||
422 | V4L2_MPEG_STREAM_TYPE_MPEG_ELEM); | ||
423 | case V4L2_CID_MPEG_VIDEO_ENCODING: | ||
424 | return v4l2_ctrl_query_fill(ctrl, | ||
425 | V4L2_MPEG_VIDEO_ENCODING_MPEG_1, | ||
426 | V4L2_MPEG_VIDEO_ENCODING_MPEG_4, 1, | ||
427 | V4L2_MPEG_VIDEO_ENCODING_MPEG_2); | ||
428 | case V4L2_CID_MPEG_VIDEO_ASPECT: | ||
429 | return v4l2_ctrl_query_fill(ctrl, | ||
430 | V4L2_MPEG_VIDEO_ASPECT_1x1, | ||
431 | V4L2_MPEG_VIDEO_ASPECT_16x9, 1, | ||
432 | V4L2_MPEG_VIDEO_ASPECT_1x1); | ||
433 | case V4L2_CID_MPEG_VIDEO_GOP_SIZE: | ||
434 | return v4l2_ctrl_query_fill(ctrl, 0, 34, 1, 15); | ||
435 | case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: | ||
436 | return v4l2_ctrl_query_fill(ctrl, 0, 1, 1, 0); | ||
437 | case V4L2_CID_MPEG_VIDEO_BITRATE: | ||
438 | return v4l2_ctrl_query_fill(ctrl, | ||
439 | 64000, | ||
440 | 10000000, 1, | ||
441 | 1500000); | ||
442 | default: | ||
443 | return -EINVAL; | ||
444 | } | ||
445 | return 0; | ||
446 | } | ||
447 | |||
448 | static int mpeg_s_ctrl(struct v4l2_control *ctrl, struct go7007 *go) | ||
449 | { | ||
450 | /* pretty sure we can't change any of these while streaming */ | ||
451 | if (go->streaming) | ||
452 | return -EBUSY; | ||
453 | |||
454 | switch (ctrl->id) { | ||
455 | case V4L2_CID_MPEG_STREAM_TYPE: | ||
456 | switch (ctrl->value) { | ||
457 | case V4L2_MPEG_STREAM_TYPE_MPEG2_DVD: | ||
458 | go->format = GO7007_FORMAT_MPEG2; | ||
459 | go->bitrate = 9800000; | ||
460 | go->gop_size = 15; | ||
461 | go->pali = 0x48; | ||
462 | go->closed_gop = 1; | ||
463 | go->repeat_seqhead = 0; | ||
464 | go->seq_header_enable = 1; | ||
465 | go->gop_header_enable = 1; | ||
466 | go->dvd_mode = 1; | ||
467 | break; | ||
468 | case V4L2_MPEG_STREAM_TYPE_MPEG_ELEM: | ||
469 | /* todo: */ | ||
470 | break; | ||
471 | default: | ||
472 | return -EINVAL; | ||
473 | } | ||
474 | break; | ||
475 | case V4L2_CID_MPEG_VIDEO_ENCODING: | ||
476 | switch (ctrl->value) { | ||
477 | case V4L2_MPEG_VIDEO_ENCODING_MPEG_1: | ||
478 | go->format = GO7007_FORMAT_MPEG1; | ||
479 | go->pali = 0; | ||
480 | break; | ||
481 | case V4L2_MPEG_VIDEO_ENCODING_MPEG_2: | ||
482 | go->format = GO7007_FORMAT_MPEG2; | ||
483 | /*if (mpeg->pali >> 24 == 2) | ||
484 | go->pali = mpeg->pali & 0xff; | ||
485 | else*/ | ||
486 | go->pali = 0x48; | ||
487 | break; | ||
488 | case V4L2_MPEG_VIDEO_ENCODING_MPEG_4: | ||
489 | go->format = GO7007_FORMAT_MPEG4; | ||
490 | /*if (mpeg->pali >> 24 == 4) | ||
491 | go->pali = mpeg->pali & 0xff; | ||
492 | else*/ | ||
493 | go->pali = 0xf5; | ||
494 | break; | ||
495 | default: | ||
496 | return -EINVAL; | ||
497 | } | ||
498 | go->gop_header_enable = | ||
499 | /*mpeg->flags & GO7007_MPEG_OMIT_GOP_HEADER | ||
500 | ? 0 :*/ 1; | ||
501 | /*if (mpeg->flags & GO7007_MPEG_REPEAT_SEQHEADER) | ||
502 | go->repeat_seqhead = 1; | ||
503 | else*/ | ||
504 | go->repeat_seqhead = 0; | ||
505 | go->dvd_mode = 0; | ||
506 | break; | ||
507 | case V4L2_CID_MPEG_VIDEO_ASPECT: | ||
508 | if (go->format == GO7007_FORMAT_MJPEG) | ||
509 | return -EINVAL; | ||
510 | switch (ctrl->value) { | ||
511 | case V4L2_MPEG_VIDEO_ASPECT_1x1: | ||
512 | go->aspect_ratio = GO7007_RATIO_1_1; | ||
513 | break; | ||
514 | case V4L2_MPEG_VIDEO_ASPECT_4x3: | ||
515 | go->aspect_ratio = GO7007_RATIO_4_3; | ||
516 | break; | ||
517 | case V4L2_MPEG_VIDEO_ASPECT_16x9: | ||
518 | go->aspect_ratio = GO7007_RATIO_16_9; | ||
519 | break; | ||
520 | case V4L2_MPEG_VIDEO_ASPECT_221x100: | ||
521 | default: | ||
522 | return -EINVAL; | ||
523 | } | ||
524 | break; | ||
525 | case V4L2_CID_MPEG_VIDEO_GOP_SIZE: | ||
526 | if (ctrl->value < 0 || ctrl->value > 34) | ||
527 | return -EINVAL; | ||
528 | go->gop_size = ctrl->value; | ||
529 | break; | ||
530 | case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: | ||
531 | if (ctrl->value != 0 && ctrl->value != 1) | ||
532 | return -EINVAL; | ||
533 | go->closed_gop = ctrl->value; | ||
534 | break; | ||
535 | case V4L2_CID_MPEG_VIDEO_BITRATE: | ||
536 | /* Upper bound is kind of arbitrary here */ | ||
537 | if (ctrl->value < 64000 || ctrl->value > 10000000) | ||
538 | return -EINVAL; | ||
539 | go->bitrate = ctrl->value; | ||
540 | break; | ||
541 | default: | ||
542 | return -EINVAL; | ||
543 | } | ||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | static int mpeg_g_ctrl(struct v4l2_control *ctrl, struct go7007 *go) | ||
548 | { | ||
549 | switch (ctrl->id) { | ||
550 | case V4L2_CID_MPEG_STREAM_TYPE: | ||
551 | if (go->dvd_mode) | ||
552 | ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG2_DVD; | ||
553 | else | ||
554 | ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG_ELEM; | ||
555 | break; | ||
556 | case V4L2_CID_MPEG_VIDEO_ENCODING: | ||
557 | switch (go->format) { | ||
558 | case GO7007_FORMAT_MPEG1: | ||
559 | ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_1; | ||
560 | break; | ||
561 | case GO7007_FORMAT_MPEG2: | ||
562 | ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_2; | ||
563 | break; | ||
564 | case GO7007_FORMAT_MPEG4: | ||
565 | ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_4; | ||
566 | break; | ||
567 | default: | ||
568 | return -EINVAL; | ||
569 | } | ||
570 | break; | ||
571 | case V4L2_CID_MPEG_VIDEO_ASPECT: | ||
572 | switch (go->aspect_ratio) { | ||
573 | case GO7007_RATIO_1_1: | ||
574 | ctrl->value = V4L2_MPEG_VIDEO_ASPECT_1x1; | ||
575 | break; | ||
576 | case GO7007_RATIO_4_3: | ||
577 | ctrl->value = V4L2_MPEG_VIDEO_ASPECT_4x3; | ||
578 | break; | ||
579 | case GO7007_RATIO_16_9: | ||
580 | ctrl->value = V4L2_MPEG_VIDEO_ASPECT_16x9; | ||
581 | break; | ||
582 | default: | ||
583 | return -EINVAL; | ||
584 | } | ||
585 | break; | ||
586 | case V4L2_CID_MPEG_VIDEO_GOP_SIZE: | ||
587 | ctrl->value = go->gop_size; | ||
588 | break; | ||
589 | case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: | ||
590 | ctrl->value = go->closed_gop; | ||
591 | break; | ||
592 | case V4L2_CID_MPEG_VIDEO_BITRATE: | ||
593 | ctrl->value = go->bitrate; | ||
594 | break; | ||
595 | default: | ||
596 | return -EINVAL; | ||
597 | } | ||
598 | return 0; | ||
599 | } | ||
600 | |||
601 | static int vidioc_querycap(struct file *file, void *priv, | ||
602 | struct v4l2_capability *cap) | ||
603 | { | ||
604 | struct go7007 *go = ((struct go7007_file *) priv)->go; | ||
605 | |||
606 | strlcpy(cap->driver, "go7007", sizeof(cap->driver)); | ||
607 | strlcpy(cap->card, go->name, sizeof(cap->card)); | ||
608 | #if 0 | ||
609 | strlcpy(cap->bus_info, dev_name(&dev->udev->dev), sizeof(cap->bus_info)); | ||
610 | #endif | ||
611 | |||
612 | cap->version = KERNEL_VERSION(0, 9, 8); | ||
613 | |||
614 | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | | ||
615 | V4L2_CAP_STREAMING; /* | V4L2_CAP_AUDIO; */ | ||
616 | |||
617 | if (go->board_info->flags & GO7007_BOARD_HAS_TUNER) | ||
618 | cap->capabilities |= V4L2_CAP_TUNER; | ||
619 | |||
620 | return 0; | ||
621 | } | ||
622 | |||
623 | static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, | ||
624 | struct v4l2_fmtdesc *fmt) | ||
625 | { | ||
626 | char *desc = NULL; | ||
627 | |||
628 | switch (fmt->index) { | ||
629 | case 0: | ||
630 | fmt->pixelformat = V4L2_PIX_FMT_MJPEG; | ||
631 | desc = "Motion-JPEG"; | ||
632 | break; | ||
633 | case 1: | ||
634 | fmt->pixelformat = V4L2_PIX_FMT_MPEG; | ||
635 | desc = "MPEG1/MPEG2/MPEG4"; | ||
636 | break; | ||
637 | default: | ||
638 | return -EINVAL; | ||
639 | } | ||
640 | fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
641 | fmt->flags = V4L2_FMT_FLAG_COMPRESSED; | ||
642 | |||
643 | strncpy(fmt->description, desc, sizeof(fmt->description)); | ||
644 | |||
645 | return 0; | ||
646 | } | ||
647 | |||
648 | static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, | ||
649 | struct v4l2_format *fmt) | ||
650 | { | ||
651 | struct go7007 *go = ((struct go7007_file *) priv)->go; | ||
652 | |||
653 | fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
654 | fmt->fmt.pix.width = go->width; | ||
655 | fmt->fmt.pix.height = go->height; | ||
656 | fmt->fmt.pix.pixelformat = (go->format == GO7007_FORMAT_MJPEG) ? | ||
657 | V4L2_PIX_FMT_MJPEG : V4L2_PIX_FMT_MPEG; | ||
658 | fmt->fmt.pix.field = V4L2_FIELD_NONE; | ||
659 | fmt->fmt.pix.bytesperline = 0; | ||
660 | fmt->fmt.pix.sizeimage = GO7007_BUF_SIZE; | ||
661 | fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; | ||
662 | |||
663 | return 0; | ||
664 | } | ||
665 | |||
666 | static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, | ||
667 | struct v4l2_format *fmt) | ||
668 | { | ||
669 | struct go7007 *go = ((struct go7007_file *) priv)->go; | ||
670 | |||
671 | return set_capture_size(go, fmt, 1); | ||
672 | } | ||
673 | |||
674 | static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, | ||
675 | struct v4l2_format *fmt) | ||
676 | { | ||
677 | struct go7007 *go = ((struct go7007_file *) priv)->go; | ||
678 | |||
679 | if (go->streaming) | ||
680 | return -EBUSY; | ||
681 | |||
682 | return set_capture_size(go, fmt, 0); | ||
683 | } | ||
684 | |||
685 | static int vidioc_reqbufs(struct file *file, void *priv, | ||
686 | struct v4l2_requestbuffers *req) | ||
687 | { | ||
688 | struct go7007_file *gofh = priv; | ||
689 | struct go7007 *go = gofh->go; | ||
690 | int retval = -EBUSY; | ||
691 | unsigned int count, i; | ||
692 | |||
693 | if (go->streaming) | ||
694 | return retval; | ||
695 | |||
696 | if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | ||
697 | req->memory != V4L2_MEMORY_MMAP) | ||
698 | return -EINVAL; | ||
699 | |||
700 | mutex_lock(&gofh->lock); | ||
701 | for (i = 0; i < gofh->buf_count; ++i) | ||
702 | if (gofh->bufs[i].mapped > 0) | ||
703 | goto unlock_and_return; | ||
704 | |||
705 | mutex_lock(&go->hw_lock); | ||
706 | if (go->in_use > 0 && gofh->buf_count == 0) { | ||
707 | mutex_unlock(&go->hw_lock); | ||
708 | goto unlock_and_return; | ||
709 | } | ||
710 | |||
711 | if (gofh->buf_count > 0) | ||
712 | kfree(gofh->bufs); | ||
713 | |||
714 | retval = -ENOMEM; | ||
715 | count = req->count; | ||
716 | if (count > 0) { | ||
717 | if (count < 2) | ||
718 | count = 2; | ||
719 | if (count > 32) | ||
720 | count = 32; | ||
721 | |||
722 | gofh->bufs = kcalloc(count, sizeof(struct go7007_buffer), | ||
723 | GFP_KERNEL); | ||
724 | |||
725 | if (!gofh->bufs) { | ||
726 | mutex_unlock(&go->hw_lock); | ||
727 | goto unlock_and_return; | ||
728 | } | ||
729 | |||
730 | for (i = 0; i < count; ++i) { | ||
731 | gofh->bufs[i].go = go; | ||
732 | gofh->bufs[i].index = i; | ||
733 | gofh->bufs[i].state = BUF_STATE_IDLE; | ||
734 | gofh->bufs[i].mapped = 0; | ||
735 | } | ||
736 | |||
737 | go->in_use = 1; | ||
738 | } else { | ||
739 | go->in_use = 0; | ||
740 | } | ||
741 | |||
742 | gofh->buf_count = count; | ||
743 | mutex_unlock(&go->hw_lock); | ||
744 | mutex_unlock(&gofh->lock); | ||
745 | |||
746 | memset(req, 0, sizeof(*req)); | ||
747 | |||
748 | req->count = count; | ||
749 | req->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
750 | req->memory = V4L2_MEMORY_MMAP; | ||
751 | |||
752 | return 0; | ||
753 | |||
754 | unlock_and_return: | ||
755 | mutex_unlock(&gofh->lock); | ||
756 | return retval; | ||
757 | } | ||
758 | |||
759 | static int vidioc_querybuf(struct file *file, void *priv, | ||
760 | struct v4l2_buffer *buf) | ||
761 | { | ||
762 | struct go7007_file *gofh = priv; | ||
763 | int retval = -EINVAL; | ||
764 | unsigned int index; | ||
765 | |||
766 | if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
767 | return retval; | ||
768 | |||
769 | index = buf->index; | ||
770 | |||
771 | mutex_lock(&gofh->lock); | ||
772 | if (index >= gofh->buf_count) | ||
773 | goto unlock_and_return; | ||
774 | |||
775 | memset(buf, 0, sizeof(*buf)); | ||
776 | buf->index = index; | ||
777 | buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
778 | |||
779 | switch (gofh->bufs[index].state) { | ||
780 | case BUF_STATE_QUEUED: | ||
781 | buf->flags = V4L2_BUF_FLAG_QUEUED; | ||
782 | break; | ||
783 | case BUF_STATE_DONE: | ||
784 | buf->flags = V4L2_BUF_FLAG_DONE; | ||
785 | break; | ||
786 | default: | ||
787 | buf->flags = 0; | ||
788 | } | ||
789 | |||
790 | if (gofh->bufs[index].mapped) | ||
791 | buf->flags |= V4L2_BUF_FLAG_MAPPED; | ||
792 | buf->memory = V4L2_MEMORY_MMAP; | ||
793 | buf->m.offset = index * GO7007_BUF_SIZE; | ||
794 | buf->length = GO7007_BUF_SIZE; | ||
795 | mutex_unlock(&gofh->lock); | ||
796 | |||
797 | return 0; | ||
798 | |||
799 | unlock_and_return: | ||
800 | mutex_unlock(&gofh->lock); | ||
801 | return retval; | ||
802 | } | ||
803 | |||
804 | static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) | ||
805 | { | ||
806 | struct go7007_file *gofh = priv; | ||
807 | struct go7007 *go = gofh->go; | ||
808 | struct go7007_buffer *gobuf; | ||
809 | unsigned long flags; | ||
810 | int retval = -EINVAL; | ||
811 | int ret; | ||
812 | |||
813 | if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | ||
814 | buf->memory != V4L2_MEMORY_MMAP) | ||
815 | return retval; | ||
816 | |||
817 | mutex_lock(&gofh->lock); | ||
818 | if (buf->index < 0 || buf->index >= gofh->buf_count) | ||
819 | goto unlock_and_return; | ||
820 | |||
821 | gobuf = &gofh->bufs[buf->index]; | ||
822 | if (!gobuf->mapped) | ||
823 | goto unlock_and_return; | ||
824 | |||
825 | retval = -EBUSY; | ||
826 | if (gobuf->state != BUF_STATE_IDLE) | ||
827 | goto unlock_and_return; | ||
828 | |||
829 | /* offset will be 0 until we really support USERPTR streaming */ | ||
830 | gobuf->offset = gobuf->user_addr & ~PAGE_MASK; | ||
831 | gobuf->bytesused = 0; | ||
832 | gobuf->frame_offset = 0; | ||
833 | gobuf->modet_active = 0; | ||
834 | if (gobuf->offset > 0) | ||
835 | gobuf->page_count = GO7007_BUF_PAGES + 1; | ||
836 | else | ||
837 | gobuf->page_count = GO7007_BUF_PAGES; | ||
838 | |||
839 | retval = -ENOMEM; | ||
840 | down_read(¤t->mm->mmap_sem); | ||
841 | ret = get_user_pages(current, current->mm, | ||
842 | gobuf->user_addr & PAGE_MASK, gobuf->page_count, | ||
843 | 1, 1, gobuf->pages, NULL); | ||
844 | up_read(¤t->mm->mmap_sem); | ||
845 | |||
846 | if (ret != gobuf->page_count) { | ||
847 | int i; | ||
848 | for (i = 0; i < ret; ++i) | ||
849 | page_cache_release(gobuf->pages[i]); | ||
850 | gobuf->page_count = 0; | ||
851 | goto unlock_and_return; | ||
852 | } | ||
853 | |||
854 | gobuf->state = BUF_STATE_QUEUED; | ||
855 | spin_lock_irqsave(&go->spinlock, flags); | ||
856 | list_add_tail(&gobuf->stream, &go->stream); | ||
857 | spin_unlock_irqrestore(&go->spinlock, flags); | ||
858 | mutex_unlock(&gofh->lock); | ||
859 | |||
860 | return 0; | ||
861 | |||
862 | unlock_and_return: | ||
863 | mutex_unlock(&gofh->lock); | ||
864 | return retval; | ||
865 | } | ||
866 | |||
867 | |||
868 | static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) | ||
869 | { | ||
870 | struct go7007_file *gofh = priv; | ||
871 | struct go7007 *go = gofh->go; | ||
872 | struct go7007_buffer *gobuf; | ||
873 | int retval = -EINVAL; | ||
874 | unsigned long flags; | ||
875 | u32 frame_type_flag; | ||
876 | DEFINE_WAIT(wait); | ||
877 | |||
878 | if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
879 | return retval; | ||
880 | if (buf->memory != V4L2_MEMORY_MMAP) | ||
881 | return retval; | ||
882 | |||
883 | mutex_lock(&gofh->lock); | ||
884 | if (list_empty(&go->stream)) | ||
885 | goto unlock_and_return; | ||
886 | gobuf = list_entry(go->stream.next, | ||
887 | struct go7007_buffer, stream); | ||
888 | |||
889 | retval = -EAGAIN; | ||
890 | if (gobuf->state != BUF_STATE_DONE && | ||
891 | !(file->f_flags & O_NONBLOCK)) { | ||
892 | for (;;) { | ||
893 | prepare_to_wait(&go->frame_waitq, &wait, | ||
894 | TASK_INTERRUPTIBLE); | ||
895 | if (gobuf->state == BUF_STATE_DONE) | ||
896 | break; | ||
897 | if (signal_pending(current)) { | ||
898 | retval = -ERESTARTSYS; | ||
899 | break; | ||
900 | } | ||
901 | schedule(); | ||
902 | } | ||
903 | finish_wait(&go->frame_waitq, &wait); | ||
904 | } | ||
905 | if (gobuf->state != BUF_STATE_DONE) | ||
906 | goto unlock_and_return; | ||
907 | |||
908 | spin_lock_irqsave(&go->spinlock, flags); | ||
909 | deactivate_buffer(gobuf); | ||
910 | spin_unlock_irqrestore(&go->spinlock, flags); | ||
911 | frame_type_flag = get_frame_type_flag(gobuf, go->format); | ||
912 | gobuf->state = BUF_STATE_IDLE; | ||
913 | |||
914 | memset(buf, 0, sizeof(*buf)); | ||
915 | buf->index = gobuf->index; | ||
916 | buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
917 | buf->bytesused = gobuf->bytesused; | ||
918 | buf->flags = V4L2_BUF_FLAG_MAPPED | frame_type_flag; | ||
919 | buf->field = V4L2_FIELD_NONE; | ||
920 | buf->timestamp = gobuf->timestamp; | ||
921 | buf->sequence = gobuf->seq; | ||
922 | buf->memory = V4L2_MEMORY_MMAP; | ||
923 | buf->m.offset = gobuf->index * GO7007_BUF_SIZE; | ||
924 | buf->length = GO7007_BUF_SIZE; | ||
925 | buf->reserved = gobuf->modet_active; | ||
926 | |||
927 | mutex_unlock(&gofh->lock); | ||
928 | return 0; | ||
929 | |||
930 | unlock_and_return: | ||
931 | mutex_unlock(&gofh->lock); | ||
932 | return retval; | ||
933 | } | ||
934 | |||
935 | static int vidioc_streamon(struct file *file, void *priv, | ||
936 | enum v4l2_buf_type type) | ||
937 | { | ||
938 | struct go7007_file *gofh = priv; | ||
939 | struct go7007 *go = gofh->go; | ||
940 | int retval = 0; | ||
941 | |||
942 | if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
943 | return -EINVAL; | ||
944 | |||
945 | mutex_lock(&gofh->lock); | ||
946 | mutex_lock(&go->hw_lock); | ||
947 | |||
948 | if (!go->streaming) { | ||
949 | go->streaming = 1; | ||
950 | go->next_seq = 0; | ||
951 | go->active_buf = NULL; | ||
952 | if (go7007_start_encoder(go) < 0) | ||
953 | retval = -EIO; | ||
954 | else | ||
955 | retval = 0; | ||
956 | } | ||
957 | mutex_unlock(&go->hw_lock); | ||
958 | mutex_unlock(&gofh->lock); | ||
959 | |||
960 | return retval; | ||
961 | } | ||
962 | |||
963 | static int vidioc_streamoff(struct file *file, void *priv, | ||
964 | enum v4l2_buf_type type) | ||
965 | { | ||
966 | struct go7007_file *gofh = priv; | ||
967 | struct go7007 *go = gofh->go; | ||
968 | |||
969 | if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
970 | return -EINVAL; | ||
971 | mutex_lock(&gofh->lock); | ||
972 | go7007_streamoff(go); | ||
973 | mutex_unlock(&gofh->lock); | ||
974 | |||
975 | return 0; | ||
976 | } | ||
977 | |||
978 | static int vidioc_queryctrl(struct file *file, void *priv, | ||
979 | struct v4l2_queryctrl *query) | ||
980 | { | ||
981 | struct go7007 *go = ((struct go7007_file *) priv)->go; | ||
982 | int id = query->id; | ||
983 | |||
984 | if (0 == call_all(&go->v4l2_dev, core, queryctrl, query)) | ||
985 | return 0; | ||
986 | |||
987 | query->id = id; | ||
988 | return mpeg_query_ctrl(query); | ||
989 | } | ||
990 | |||
991 | static int vidioc_g_ctrl(struct file *file, void *priv, | ||
992 | struct v4l2_control *ctrl) | ||
993 | { | ||
994 | struct go7007 *go = ((struct go7007_file *) priv)->go; | ||
995 | |||
996 | if (0 == call_all(&go->v4l2_dev, core, g_ctrl, ctrl)) | ||
997 | return 0; | ||
998 | |||
999 | return mpeg_g_ctrl(ctrl, go); | ||
1000 | } | ||
1001 | |||
1002 | static int vidioc_s_ctrl(struct file *file, void *priv, | ||
1003 | struct v4l2_control *ctrl) | ||
1004 | { | ||
1005 | struct go7007 *go = ((struct go7007_file *) priv)->go; | ||
1006 | |||
1007 | if (0 == call_all(&go->v4l2_dev, core, s_ctrl, ctrl)) | ||
1008 | return 0; | ||
1009 | |||
1010 | return mpeg_s_ctrl(ctrl, go); | ||
1011 | } | ||
1012 | |||
1013 | static int vidioc_g_parm(struct file *filp, void *priv, | ||
1014 | struct v4l2_streamparm *parm) | ||
1015 | { | ||
1016 | struct go7007 *go = ((struct go7007_file *) priv)->go; | ||
1017 | struct v4l2_fract timeperframe = { | ||
1018 | .numerator = 1001 * go->fps_scale, | ||
1019 | .denominator = go->sensor_framerate, | ||
1020 | }; | ||
1021 | |||
1022 | if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
1023 | return -EINVAL; | ||
1024 | |||
1025 | parm->parm.capture.capability |= V4L2_CAP_TIMEPERFRAME; | ||
1026 | parm->parm.capture.timeperframe = timeperframe; | ||
1027 | |||
1028 | return 0; | ||
1029 | } | ||
1030 | |||
1031 | static int vidioc_s_parm(struct file *filp, void *priv, | ||
1032 | struct v4l2_streamparm *parm) | ||
1033 | { | ||
1034 | struct go7007 *go = ((struct go7007_file *) priv)->go; | ||
1035 | unsigned int n, d; | ||
1036 | |||
1037 | if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
1038 | return -EINVAL; | ||
1039 | if (parm->parm.capture.capturemode != 0) | ||
1040 | return -EINVAL; | ||
1041 | |||
1042 | n = go->sensor_framerate * | ||
1043 | parm->parm.capture.timeperframe.numerator; | ||
1044 | d = 1001 * parm->parm.capture.timeperframe.denominator; | ||
1045 | if (n != 0 && d != 0 && n > d) | ||
1046 | go->fps_scale = (n + d/2) / d; | ||
1047 | else | ||
1048 | go->fps_scale = 1; | ||
1049 | |||
1050 | return 0; | ||
1051 | } | ||
1052 | |||
1053 | /* VIDIOC_ENUMSTD on go7007 were used for enumberating the supported fps and | ||
1054 | its resolution, when the device is not connected to TV. | ||
1055 | This were an API abuse, probably used by the lack of specific IOCTL's to | ||
1056 | enumberate it, by the time the driver were written. | ||
1057 | |||
1058 | However, since kernel 2.6.19, two new ioctls (VIDIOC_ENUM_FRAMEINTERVALS | ||
1059 | and VIDIOC_ENUM_FRAMESIZES) were added for this purpose. | ||
1060 | |||
1061 | The two functions bellow implements the newer ioctls | ||
1062 | */ | ||
1063 | static int vidioc_enum_framesizes(struct file *filp, void *priv, | ||
1064 | struct v4l2_frmsizeenum *fsize) | ||
1065 | { | ||
1066 | struct go7007 *go = ((struct go7007_file *) priv)->go; | ||
1067 | |||
1068 | /* Return -EINVAL, if it is a TV board */ | ||
1069 | if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) || | ||
1070 | (go->board_info->sensor_flags & GO7007_SENSOR_TV)) | ||
1071 | return -EINVAL; | ||
1072 | |||
1073 | if (fsize->index > 0) | ||
1074 | return -EINVAL; | ||
1075 | |||
1076 | fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; | ||
1077 | fsize->discrete.width = go->board_info->sensor_width; | ||
1078 | fsize->discrete.height = go->board_info->sensor_height; | ||
1079 | |||
1080 | return 0; | ||
1081 | } | ||
1082 | |||
1083 | static int vidioc_enum_frameintervals(struct file *filp, void *priv, | ||
1084 | struct v4l2_frmivalenum *fival) | ||
1085 | { | ||
1086 | struct go7007 *go = ((struct go7007_file *) priv)->go; | ||
1087 | |||
1088 | /* Return -EINVAL, if it is a TV board */ | ||
1089 | if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) || | ||
1090 | (go->board_info->sensor_flags & GO7007_SENSOR_TV)) | ||
1091 | return -EINVAL; | ||
1092 | |||
1093 | if (fival->index > 0) | ||
1094 | return -EINVAL; | ||
1095 | |||
1096 | fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; | ||
1097 | fival->discrete.numerator = 1001; | ||
1098 | fival->discrete.denominator = go->board_info->sensor_framerate; | ||
1099 | |||
1100 | return 0; | ||
1101 | } | ||
1102 | |||
1103 | static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std) | ||
1104 | { | ||
1105 | struct go7007 *go = ((struct go7007_file *) priv)->go; | ||
1106 | |||
1107 | switch (go->standard) { | ||
1108 | case GO7007_STD_NTSC: | ||
1109 | *std = V4L2_STD_NTSC; | ||
1110 | break; | ||
1111 | case GO7007_STD_PAL: | ||
1112 | *std = V4L2_STD_PAL; | ||
1113 | break; | ||
1114 | default: | ||
1115 | return -EINVAL; | ||
1116 | } | ||
1117 | |||
1118 | return 0; | ||
1119 | } | ||
1120 | |||
1121 | static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *std) | ||
1122 | { | ||
1123 | struct go7007 *go = ((struct go7007_file *) priv)->go; | ||
1124 | |||
1125 | if (go->streaming) | ||
1126 | return -EBUSY; | ||
1127 | |||
1128 | if (!(go->board_info->sensor_flags & GO7007_SENSOR_TV) && *std != 0) | ||
1129 | return -EINVAL; | ||
1130 | |||
1131 | if (*std == 0) | ||
1132 | return -EINVAL; | ||
1133 | |||
1134 | if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) && | ||
1135 | go->input == go->board_info->num_inputs - 1) { | ||
1136 | if (!go->i2c_adapter_online) | ||
1137 | return -EIO; | ||
1138 | if (call_all(&go->v4l2_dev, core, s_std, *std) < 0) | ||
1139 | return -EINVAL; | ||
1140 | } | ||
1141 | |||
1142 | if (*std & V4L2_STD_NTSC) { | ||
1143 | go->standard = GO7007_STD_NTSC; | ||
1144 | go->sensor_framerate = 30000; | ||
1145 | } else if (*std & V4L2_STD_PAL) { | ||
1146 | go->standard = GO7007_STD_PAL; | ||
1147 | go->sensor_framerate = 25025; | ||
1148 | } else if (*std & V4L2_STD_SECAM) { | ||
1149 | go->standard = GO7007_STD_PAL; | ||
1150 | go->sensor_framerate = 25025; | ||
1151 | } else | ||
1152 | return -EINVAL; | ||
1153 | |||
1154 | call_all(&go->v4l2_dev, core, s_std, *std); | ||
1155 | set_capture_size(go, NULL, 0); | ||
1156 | |||
1157 | return 0; | ||
1158 | } | ||
1159 | |||
1160 | static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *std) | ||
1161 | { | ||
1162 | struct go7007 *go = ((struct go7007_file *) priv)->go; | ||
1163 | |||
1164 | if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) && | ||
1165 | go->input == go->board_info->num_inputs - 1) { | ||
1166 | if (!go->i2c_adapter_online) | ||
1167 | return -EIO; | ||
1168 | return call_all(&go->v4l2_dev, video, querystd, std); | ||
1169 | } else if (go->board_info->sensor_flags & GO7007_SENSOR_TV) | ||
1170 | *std = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM; | ||
1171 | else | ||
1172 | *std = 0; | ||
1173 | |||
1174 | return 0; | ||
1175 | } | ||
1176 | |||
1177 | static int vidioc_enum_input(struct file *file, void *priv, | ||
1178 | struct v4l2_input *inp) | ||
1179 | { | ||
1180 | struct go7007 *go = ((struct go7007_file *) priv)->go; | ||
1181 | |||
1182 | if (inp->index >= go->board_info->num_inputs) | ||
1183 | return -EINVAL; | ||
1184 | |||
1185 | strncpy(inp->name, go->board_info->inputs[inp->index].name, | ||
1186 | sizeof(inp->name)); | ||
1187 | |||
1188 | /* If this board has a tuner, it will be the last input */ | ||
1189 | if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) && | ||
1190 | inp->index == go->board_info->num_inputs - 1) | ||
1191 | inp->type = V4L2_INPUT_TYPE_TUNER; | ||
1192 | else | ||
1193 | inp->type = V4L2_INPUT_TYPE_CAMERA; | ||
1194 | |||
1195 | inp->audioset = 0; | ||
1196 | inp->tuner = 0; | ||
1197 | if (go->board_info->sensor_flags & GO7007_SENSOR_TV) | ||
1198 | inp->std = V4L2_STD_NTSC | V4L2_STD_PAL | | ||
1199 | V4L2_STD_SECAM; | ||
1200 | else | ||
1201 | inp->std = 0; | ||
1202 | |||
1203 | return 0; | ||
1204 | } | ||
1205 | |||
1206 | |||
1207 | static int vidioc_g_input(struct file *file, void *priv, unsigned int *input) | ||
1208 | { | ||
1209 | struct go7007 *go = ((struct go7007_file *) priv)->go; | ||
1210 | |||
1211 | *input = go->input; | ||
1212 | |||
1213 | return 0; | ||
1214 | } | ||
1215 | |||
1216 | static int vidioc_s_input(struct file *file, void *priv, unsigned int input) | ||
1217 | { | ||
1218 | struct go7007 *go = ((struct go7007_file *) priv)->go; | ||
1219 | |||
1220 | if (input >= go->board_info->num_inputs) | ||
1221 | return -EINVAL; | ||
1222 | if (go->streaming) | ||
1223 | return -EBUSY; | ||
1224 | |||
1225 | go->input = input; | ||
1226 | |||
1227 | return call_all(&go->v4l2_dev, video, s_routing, input, 0, 0); | ||
1228 | } | ||
1229 | |||
1230 | static int vidioc_g_tuner(struct file *file, void *priv, | ||
1231 | struct v4l2_tuner *t) | ||
1232 | { | ||
1233 | struct go7007 *go = ((struct go7007_file *) priv)->go; | ||
1234 | |||
1235 | if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER)) | ||
1236 | return -EINVAL; | ||
1237 | if (t->index != 0) | ||
1238 | return -EINVAL; | ||
1239 | if (!go->i2c_adapter_online) | ||
1240 | return -EIO; | ||
1241 | |||
1242 | return call_all(&go->v4l2_dev, tuner, g_tuner, t); | ||
1243 | } | ||
1244 | |||
1245 | static int vidioc_s_tuner(struct file *file, void *priv, | ||
1246 | struct v4l2_tuner *t) | ||
1247 | { | ||
1248 | struct go7007 *go = ((struct go7007_file *) priv)->go; | ||
1249 | |||
1250 | if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER)) | ||
1251 | return -EINVAL; | ||
1252 | if (t->index != 0) | ||
1253 | return -EINVAL; | ||
1254 | if (!go->i2c_adapter_online) | ||
1255 | return -EIO; | ||
1256 | |||
1257 | switch (go->board_id) { | ||
1258 | case GO7007_BOARDID_PX_TV402U_NA: | ||
1259 | case GO7007_BOARDID_PX_TV402U_JP: | ||
1260 | /* No selectable options currently */ | ||
1261 | if (t->audmode != V4L2_TUNER_MODE_STEREO) | ||
1262 | return -EINVAL; | ||
1263 | break; | ||
1264 | } | ||
1265 | |||
1266 | return call_all(&go->v4l2_dev, tuner, s_tuner, t); | ||
1267 | } | ||
1268 | |||
1269 | static int vidioc_g_frequency(struct file *file, void *priv, | ||
1270 | struct v4l2_frequency *f) | ||
1271 | { | ||
1272 | struct go7007 *go = ((struct go7007_file *) priv)->go; | ||
1273 | |||
1274 | if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER)) | ||
1275 | return -EINVAL; | ||
1276 | if (!go->i2c_adapter_online) | ||
1277 | return -EIO; | ||
1278 | |||
1279 | f->type = V4L2_TUNER_ANALOG_TV; | ||
1280 | |||
1281 | return call_all(&go->v4l2_dev, tuner, g_frequency, f); | ||
1282 | } | ||
1283 | |||
1284 | static int vidioc_s_frequency(struct file *file, void *priv, | ||
1285 | struct v4l2_frequency *f) | ||
1286 | { | ||
1287 | struct go7007 *go = ((struct go7007_file *) priv)->go; | ||
1288 | |||
1289 | if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER)) | ||
1290 | return -EINVAL; | ||
1291 | if (!go->i2c_adapter_online) | ||
1292 | return -EIO; | ||
1293 | |||
1294 | return call_all(&go->v4l2_dev, tuner, s_frequency, f); | ||
1295 | } | ||
1296 | |||
1297 | static int vidioc_cropcap(struct file *file, void *priv, | ||
1298 | struct v4l2_cropcap *cropcap) | ||
1299 | { | ||
1300 | struct go7007 *go = ((struct go7007_file *) priv)->go; | ||
1301 | |||
1302 | if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
1303 | return -EINVAL; | ||
1304 | |||
1305 | /* These specify the raw input of the sensor */ | ||
1306 | switch (go->standard) { | ||
1307 | case GO7007_STD_NTSC: | ||
1308 | cropcap->bounds.top = 0; | ||
1309 | cropcap->bounds.left = 0; | ||
1310 | cropcap->bounds.width = 720; | ||
1311 | cropcap->bounds.height = 480; | ||
1312 | cropcap->defrect.top = 0; | ||
1313 | cropcap->defrect.left = 0; | ||
1314 | cropcap->defrect.width = 720; | ||
1315 | cropcap->defrect.height = 480; | ||
1316 | break; | ||
1317 | case GO7007_STD_PAL: | ||
1318 | cropcap->bounds.top = 0; | ||
1319 | cropcap->bounds.left = 0; | ||
1320 | cropcap->bounds.width = 720; | ||
1321 | cropcap->bounds.height = 576; | ||
1322 | cropcap->defrect.top = 0; | ||
1323 | cropcap->defrect.left = 0; | ||
1324 | cropcap->defrect.width = 720; | ||
1325 | cropcap->defrect.height = 576; | ||
1326 | break; | ||
1327 | case GO7007_STD_OTHER: | ||
1328 | cropcap->bounds.top = 0; | ||
1329 | cropcap->bounds.left = 0; | ||
1330 | cropcap->bounds.width = go->board_info->sensor_width; | ||
1331 | cropcap->bounds.height = go->board_info->sensor_height; | ||
1332 | cropcap->defrect.top = 0; | ||
1333 | cropcap->defrect.left = 0; | ||
1334 | cropcap->defrect.width = go->board_info->sensor_width; | ||
1335 | cropcap->defrect.height = go->board_info->sensor_height; | ||
1336 | break; | ||
1337 | } | ||
1338 | |||
1339 | return 0; | ||
1340 | } | ||
1341 | |||
1342 | static int vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *crop) | ||
1343 | { | ||
1344 | struct go7007 *go = ((struct go7007_file *) priv)->go; | ||
1345 | |||
1346 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
1347 | return -EINVAL; | ||
1348 | |||
1349 | crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1350 | |||
1351 | /* These specify the raw input of the sensor */ | ||
1352 | switch (go->standard) { | ||
1353 | case GO7007_STD_NTSC: | ||
1354 | crop->c.top = 0; | ||
1355 | crop->c.left = 0; | ||
1356 | crop->c.width = 720; | ||
1357 | crop->c.height = 480; | ||
1358 | break; | ||
1359 | case GO7007_STD_PAL: | ||
1360 | crop->c.top = 0; | ||
1361 | crop->c.left = 0; | ||
1362 | crop->c.width = 720; | ||
1363 | crop->c.height = 576; | ||
1364 | break; | ||
1365 | case GO7007_STD_OTHER: | ||
1366 | crop->c.top = 0; | ||
1367 | crop->c.left = 0; | ||
1368 | crop->c.width = go->board_info->sensor_width; | ||
1369 | crop->c.height = go->board_info->sensor_height; | ||
1370 | break; | ||
1371 | } | ||
1372 | |||
1373 | return 0; | ||
1374 | } | ||
1375 | |||
1376 | /* FIXME: vidioc_s_crop is not really implemented!!! | ||
1377 | */ | ||
1378 | static int vidioc_s_crop(struct file *file, void *priv, struct v4l2_crop *crop) | ||
1379 | { | ||
1380 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
1381 | return -EINVAL; | ||
1382 | |||
1383 | return 0; | ||
1384 | } | ||
1385 | |||
1386 | static int vidioc_g_jpegcomp(struct file *file, void *priv, | ||
1387 | struct v4l2_jpegcompression *params) | ||
1388 | { | ||
1389 | memset(params, 0, sizeof(*params)); | ||
1390 | params->quality = 50; /* ?? */ | ||
1391 | params->jpeg_markers = V4L2_JPEG_MARKER_DHT | | ||
1392 | V4L2_JPEG_MARKER_DQT; | ||
1393 | |||
1394 | return 0; | ||
1395 | } | ||
1396 | |||
1397 | static int vidioc_s_jpegcomp(struct file *file, void *priv, | ||
1398 | struct v4l2_jpegcompression *params) | ||
1399 | { | ||
1400 | if (params->quality != 50 || | ||
1401 | params->jpeg_markers != (V4L2_JPEG_MARKER_DHT | | ||
1402 | V4L2_JPEG_MARKER_DQT)) | ||
1403 | return -EINVAL; | ||
1404 | |||
1405 | return 0; | ||
1406 | } | ||
1407 | |||
1408 | /* FIXME: | ||
1409 | Those ioctls are private, and not needed, since several standard | ||
1410 | extended controls already provide streaming control. | ||
1411 | So, those ioctls should be converted into vidioc_g_ext_ctrls() | ||
1412 | and vidioc_s_ext_ctrls() | ||
1413 | */ | ||
1414 | |||
1415 | #if 0 | ||
1416 | /* Temporary ioctls for controlling compression characteristics */ | ||
1417 | case GO7007IOC_S_BITRATE: | ||
1418 | { | ||
1419 | int *bitrate = arg; | ||
1420 | |||
1421 | if (go->streaming) | ||
1422 | return -EINVAL; | ||
1423 | /* Upper bound is kind of arbitrary here */ | ||
1424 | if (*bitrate < 64000 || *bitrate > 10000000) | ||
1425 | return -EINVAL; | ||
1426 | go->bitrate = *bitrate; | ||
1427 | return 0; | ||
1428 | } | ||
1429 | case GO7007IOC_G_BITRATE: | ||
1430 | { | ||
1431 | int *bitrate = arg; | ||
1432 | |||
1433 | *bitrate = go->bitrate; | ||
1434 | return 0; | ||
1435 | } | ||
1436 | case GO7007IOC_S_COMP_PARAMS: | ||
1437 | { | ||
1438 | struct go7007_comp_params *comp = arg; | ||
1439 | |||
1440 | if (go->format == GO7007_FORMAT_MJPEG) | ||
1441 | return -EINVAL; | ||
1442 | if (comp->gop_size > 0) | ||
1443 | go->gop_size = comp->gop_size; | ||
1444 | else | ||
1445 | go->gop_size = go->sensor_framerate / 1000; | ||
1446 | if (go->gop_size != 15) | ||
1447 | go->dvd_mode = 0; | ||
1448 | /*go->ipb = comp->max_b_frames > 0;*/ /* completely untested */ | ||
1449 | if (go->board_info->sensor_flags & GO7007_SENSOR_TV) { | ||
1450 | switch (comp->aspect_ratio) { | ||
1451 | case GO7007_ASPECT_RATIO_4_3_NTSC: | ||
1452 | case GO7007_ASPECT_RATIO_4_3_PAL: | ||
1453 | go->aspect_ratio = GO7007_RATIO_4_3; | ||
1454 | break; | ||
1455 | case GO7007_ASPECT_RATIO_16_9_NTSC: | ||
1456 | case GO7007_ASPECT_RATIO_16_9_PAL: | ||
1457 | go->aspect_ratio = GO7007_RATIO_16_9; | ||
1458 | break; | ||
1459 | default: | ||
1460 | go->aspect_ratio = GO7007_RATIO_1_1; | ||
1461 | break; | ||
1462 | } | ||
1463 | } | ||
1464 | if (comp->flags & GO7007_COMP_OMIT_SEQ_HEADER) { | ||
1465 | go->dvd_mode = 0; | ||
1466 | go->seq_header_enable = 0; | ||
1467 | } else { | ||
1468 | go->seq_header_enable = 1; | ||
1469 | } | ||
1470 | /* fall-through */ | ||
1471 | } | ||
1472 | case GO7007IOC_G_COMP_PARAMS: | ||
1473 | { | ||
1474 | struct go7007_comp_params *comp = arg; | ||
1475 | |||
1476 | if (go->format == GO7007_FORMAT_MJPEG) | ||
1477 | return -EINVAL; | ||
1478 | memset(comp, 0, sizeof(*comp)); | ||
1479 | comp->gop_size = go->gop_size; | ||
1480 | comp->max_b_frames = go->ipb ? 2 : 0; | ||
1481 | switch (go->aspect_ratio) { | ||
1482 | case GO7007_RATIO_4_3: | ||
1483 | if (go->standard == GO7007_STD_NTSC) | ||
1484 | comp->aspect_ratio = | ||
1485 | GO7007_ASPECT_RATIO_4_3_NTSC; | ||
1486 | else | ||
1487 | comp->aspect_ratio = | ||
1488 | GO7007_ASPECT_RATIO_4_3_PAL; | ||
1489 | break; | ||
1490 | case GO7007_RATIO_16_9: | ||
1491 | if (go->standard == GO7007_STD_NTSC) | ||
1492 | comp->aspect_ratio = | ||
1493 | GO7007_ASPECT_RATIO_16_9_NTSC; | ||
1494 | else | ||
1495 | comp->aspect_ratio = | ||
1496 | GO7007_ASPECT_RATIO_16_9_PAL; | ||
1497 | break; | ||
1498 | default: | ||
1499 | comp->aspect_ratio = GO7007_ASPECT_RATIO_1_1; | ||
1500 | break; | ||
1501 | } | ||
1502 | if (go->closed_gop) | ||
1503 | comp->flags |= GO7007_COMP_CLOSED_GOP; | ||
1504 | if (!go->seq_header_enable) | ||
1505 | comp->flags |= GO7007_COMP_OMIT_SEQ_HEADER; | ||
1506 | return 0; | ||
1507 | } | ||
1508 | case GO7007IOC_S_MPEG_PARAMS: | ||
1509 | { | ||
1510 | struct go7007_mpeg_params *mpeg = arg; | ||
1511 | |||
1512 | if (go->format != GO7007_FORMAT_MPEG1 && | ||
1513 | go->format != GO7007_FORMAT_MPEG2 && | ||
1514 | go->format != GO7007_FORMAT_MPEG4) | ||
1515 | return -EINVAL; | ||
1516 | |||
1517 | if (mpeg->flags & GO7007_MPEG_FORCE_DVD_MODE) { | ||
1518 | go->format = GO7007_FORMAT_MPEG2; | ||
1519 | go->bitrate = 9800000; | ||
1520 | go->gop_size = 15; | ||
1521 | go->pali = 0x48; | ||
1522 | go->closed_gop = 1; | ||
1523 | go->repeat_seqhead = 0; | ||
1524 | go->seq_header_enable = 1; | ||
1525 | go->gop_header_enable = 1; | ||
1526 | go->dvd_mode = 1; | ||
1527 | } else { | ||
1528 | switch (mpeg->mpeg_video_standard) { | ||
1529 | case GO7007_MPEG_VIDEO_MPEG1: | ||
1530 | go->format = GO7007_FORMAT_MPEG1; | ||
1531 | go->pali = 0; | ||
1532 | break; | ||
1533 | case GO7007_MPEG_VIDEO_MPEG2: | ||
1534 | go->format = GO7007_FORMAT_MPEG2; | ||
1535 | if (mpeg->pali >> 24 == 2) | ||
1536 | go->pali = mpeg->pali & 0xff; | ||
1537 | else | ||
1538 | go->pali = 0x48; | ||
1539 | break; | ||
1540 | case GO7007_MPEG_VIDEO_MPEG4: | ||
1541 | go->format = GO7007_FORMAT_MPEG4; | ||
1542 | if (mpeg->pali >> 24 == 4) | ||
1543 | go->pali = mpeg->pali & 0xff; | ||
1544 | else | ||
1545 | go->pali = 0xf5; | ||
1546 | break; | ||
1547 | default: | ||
1548 | return -EINVAL; | ||
1549 | } | ||
1550 | go->gop_header_enable = | ||
1551 | mpeg->flags & GO7007_MPEG_OMIT_GOP_HEADER | ||
1552 | ? 0 : 1; | ||
1553 | if (mpeg->flags & GO7007_MPEG_REPEAT_SEQHEADER) | ||
1554 | go->repeat_seqhead = 1; | ||
1555 | else | ||
1556 | go->repeat_seqhead = 0; | ||
1557 | go->dvd_mode = 0; | ||
1558 | } | ||
1559 | /* fall-through */ | ||
1560 | } | ||
1561 | case GO7007IOC_G_MPEG_PARAMS: | ||
1562 | { | ||
1563 | struct go7007_mpeg_params *mpeg = arg; | ||
1564 | |||
1565 | memset(mpeg, 0, sizeof(*mpeg)); | ||
1566 | switch (go->format) { | ||
1567 | case GO7007_FORMAT_MPEG1: | ||
1568 | mpeg->mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG1; | ||
1569 | mpeg->pali = 0; | ||
1570 | break; | ||
1571 | case GO7007_FORMAT_MPEG2: | ||
1572 | mpeg->mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG2; | ||
1573 | mpeg->pali = GO7007_MPEG_PROFILE(2, go->pali); | ||
1574 | break; | ||
1575 | case GO7007_FORMAT_MPEG4: | ||
1576 | mpeg->mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG4; | ||
1577 | mpeg->pali = GO7007_MPEG_PROFILE(4, go->pali); | ||
1578 | break; | ||
1579 | default: | ||
1580 | return -EINVAL; | ||
1581 | } | ||
1582 | if (!go->gop_header_enable) | ||
1583 | mpeg->flags |= GO7007_MPEG_OMIT_GOP_HEADER; | ||
1584 | if (go->repeat_seqhead) | ||
1585 | mpeg->flags |= GO7007_MPEG_REPEAT_SEQHEADER; | ||
1586 | if (go->dvd_mode) | ||
1587 | mpeg->flags |= GO7007_MPEG_FORCE_DVD_MODE; | ||
1588 | return 0; | ||
1589 | } | ||
1590 | case GO7007IOC_S_MD_PARAMS: | ||
1591 | { | ||
1592 | struct go7007_md_params *mdp = arg; | ||
1593 | |||
1594 | if (mdp->region > 3) | ||
1595 | return -EINVAL; | ||
1596 | if (mdp->trigger > 0) { | ||
1597 | go->modet[mdp->region].pixel_threshold = | ||
1598 | mdp->pixel_threshold >> 1; | ||
1599 | go->modet[mdp->region].motion_threshold = | ||
1600 | mdp->motion_threshold >> 1; | ||
1601 | go->modet[mdp->region].mb_threshold = | ||
1602 | mdp->trigger >> 1; | ||
1603 | go->modet[mdp->region].enable = 1; | ||
1604 | } else | ||
1605 | go->modet[mdp->region].enable = 0; | ||
1606 | /* fall-through */ | ||
1607 | } | ||
1608 | case GO7007IOC_G_MD_PARAMS: | ||
1609 | { | ||
1610 | struct go7007_md_params *mdp = arg; | ||
1611 | int region = mdp->region; | ||
1612 | |||
1613 | if (mdp->region > 3) | ||
1614 | return -EINVAL; | ||
1615 | memset(mdp, 0, sizeof(struct go7007_md_params)); | ||
1616 | mdp->region = region; | ||
1617 | if (!go->modet[region].enable) | ||
1618 | return 0; | ||
1619 | mdp->pixel_threshold = | ||
1620 | (go->modet[region].pixel_threshold << 1) + 1; | ||
1621 | mdp->motion_threshold = | ||
1622 | (go->modet[region].motion_threshold << 1) + 1; | ||
1623 | mdp->trigger = | ||
1624 | (go->modet[region].mb_threshold << 1) + 1; | ||
1625 | return 0; | ||
1626 | } | ||
1627 | case GO7007IOC_S_MD_REGION: | ||
1628 | { | ||
1629 | struct go7007_md_region *region = arg; | ||
1630 | |||
1631 | if (region->region < 1 || region->region > 3) | ||
1632 | return -EINVAL; | ||
1633 | return clip_to_modet_map(go, region->region, region->clips); | ||
1634 | } | ||
1635 | #endif | ||
1636 | |||
1637 | static ssize_t go7007_read(struct file *file, char __user *data, | ||
1638 | size_t count, loff_t *ppos) | ||
1639 | { | ||
1640 | return -EINVAL; | ||
1641 | } | ||
1642 | |||
1643 | static void go7007_vm_open(struct vm_area_struct *vma) | ||
1644 | { | ||
1645 | struct go7007_buffer *gobuf = vma->vm_private_data; | ||
1646 | |||
1647 | ++gobuf->mapped; | ||
1648 | } | ||
1649 | |||
1650 | static void go7007_vm_close(struct vm_area_struct *vma) | ||
1651 | { | ||
1652 | struct go7007_buffer *gobuf = vma->vm_private_data; | ||
1653 | unsigned long flags; | ||
1654 | |||
1655 | if (--gobuf->mapped == 0) { | ||
1656 | spin_lock_irqsave(&gobuf->go->spinlock, flags); | ||
1657 | deactivate_buffer(gobuf); | ||
1658 | spin_unlock_irqrestore(&gobuf->go->spinlock, flags); | ||
1659 | } | ||
1660 | } | ||
1661 | |||
1662 | /* Copied from videobuf-dma-sg.c */ | ||
1663 | static int go7007_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | ||
1664 | { | ||
1665 | struct page *page; | ||
1666 | |||
1667 | page = alloc_page(GFP_USER | __GFP_DMA32); | ||
1668 | if (!page) | ||
1669 | return VM_FAULT_OOM; | ||
1670 | clear_user_highpage(page, (unsigned long)vmf->virtual_address); | ||
1671 | vmf->page = page; | ||
1672 | return 0; | ||
1673 | } | ||
1674 | |||
1675 | static struct vm_operations_struct go7007_vm_ops = { | ||
1676 | .open = go7007_vm_open, | ||
1677 | .close = go7007_vm_close, | ||
1678 | .fault = go7007_vm_fault, | ||
1679 | }; | ||
1680 | |||
1681 | static int go7007_mmap(struct file *file, struct vm_area_struct *vma) | ||
1682 | { | ||
1683 | struct go7007_file *gofh = file->private_data; | ||
1684 | unsigned int index; | ||
1685 | |||
1686 | if (gofh->go->status != STATUS_ONLINE) | ||
1687 | return -EIO; | ||
1688 | if (!(vma->vm_flags & VM_SHARED)) | ||
1689 | return -EINVAL; /* only support VM_SHARED mapping */ | ||
1690 | if (vma->vm_end - vma->vm_start != GO7007_BUF_SIZE) | ||
1691 | return -EINVAL; /* must map exactly one full buffer */ | ||
1692 | mutex_lock(&gofh->lock); | ||
1693 | index = vma->vm_pgoff / GO7007_BUF_PAGES; | ||
1694 | if (index >= gofh->buf_count) { | ||
1695 | mutex_unlock(&gofh->lock); | ||
1696 | return -EINVAL; /* trying to map beyond requested buffers */ | ||
1697 | } | ||
1698 | if (index * GO7007_BUF_PAGES != vma->vm_pgoff) { | ||
1699 | mutex_unlock(&gofh->lock); | ||
1700 | return -EINVAL; /* offset is not aligned on buffer boundary */ | ||
1701 | } | ||
1702 | if (gofh->bufs[index].mapped > 0) { | ||
1703 | mutex_unlock(&gofh->lock); | ||
1704 | return -EBUSY; | ||
1705 | } | ||
1706 | gofh->bufs[index].mapped = 1; | ||
1707 | gofh->bufs[index].user_addr = vma->vm_start; | ||
1708 | vma->vm_ops = &go7007_vm_ops; | ||
1709 | vma->vm_flags |= VM_DONTEXPAND; | ||
1710 | vma->vm_flags &= ~VM_IO; | ||
1711 | vma->vm_private_data = &gofh->bufs[index]; | ||
1712 | mutex_unlock(&gofh->lock); | ||
1713 | return 0; | ||
1714 | } | ||
1715 | |||
1716 | static unsigned int go7007_poll(struct file *file, poll_table *wait) | ||
1717 | { | ||
1718 | struct go7007_file *gofh = file->private_data; | ||
1719 | struct go7007_buffer *gobuf; | ||
1720 | |||
1721 | if (list_empty(&gofh->go->stream)) | ||
1722 | return POLLERR; | ||
1723 | gobuf = list_entry(gofh->go->stream.next, struct go7007_buffer, stream); | ||
1724 | poll_wait(file, &gofh->go->frame_waitq, wait); | ||
1725 | if (gobuf->state == BUF_STATE_DONE) | ||
1726 | return POLLIN | POLLRDNORM; | ||
1727 | return 0; | ||
1728 | } | ||
1729 | |||
1730 | static void go7007_vfl_release(struct video_device *vfd) | ||
1731 | { | ||
1732 | struct go7007 *go = video_get_drvdata(vfd); | ||
1733 | |||
1734 | video_device_release(vfd); | ||
1735 | if (--go->ref_count == 0) | ||
1736 | kfree(go); | ||
1737 | } | ||
1738 | |||
1739 | static struct v4l2_file_operations go7007_fops = { | ||
1740 | .owner = THIS_MODULE, | ||
1741 | .open = go7007_open, | ||
1742 | .release = go7007_release, | ||
1743 | .ioctl = video_ioctl2, | ||
1744 | .read = go7007_read, | ||
1745 | .mmap = go7007_mmap, | ||
1746 | .poll = go7007_poll, | ||
1747 | }; | ||
1748 | |||
1749 | static const struct v4l2_ioctl_ops video_ioctl_ops = { | ||
1750 | .vidioc_querycap = vidioc_querycap, | ||
1751 | .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, | ||
1752 | .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, | ||
1753 | .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, | ||
1754 | .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, | ||
1755 | .vidioc_reqbufs = vidioc_reqbufs, | ||
1756 | .vidioc_querybuf = vidioc_querybuf, | ||
1757 | .vidioc_qbuf = vidioc_qbuf, | ||
1758 | .vidioc_dqbuf = vidioc_dqbuf, | ||
1759 | .vidioc_g_std = vidioc_g_std, | ||
1760 | .vidioc_s_std = vidioc_s_std, | ||
1761 | .vidioc_querystd = vidioc_querystd, | ||
1762 | .vidioc_enum_input = vidioc_enum_input, | ||
1763 | .vidioc_g_input = vidioc_g_input, | ||
1764 | .vidioc_s_input = vidioc_s_input, | ||
1765 | .vidioc_queryctrl = vidioc_queryctrl, | ||
1766 | .vidioc_g_ctrl = vidioc_g_ctrl, | ||
1767 | .vidioc_s_ctrl = vidioc_s_ctrl, | ||
1768 | .vidioc_streamon = vidioc_streamon, | ||
1769 | .vidioc_streamoff = vidioc_streamoff, | ||
1770 | .vidioc_g_tuner = vidioc_g_tuner, | ||
1771 | .vidioc_s_tuner = vidioc_s_tuner, | ||
1772 | .vidioc_g_frequency = vidioc_g_frequency, | ||
1773 | .vidioc_s_frequency = vidioc_s_frequency, | ||
1774 | .vidioc_g_parm = vidioc_g_parm, | ||
1775 | .vidioc_s_parm = vidioc_s_parm, | ||
1776 | .vidioc_enum_framesizes = vidioc_enum_framesizes, | ||
1777 | .vidioc_enum_frameintervals = vidioc_enum_frameintervals, | ||
1778 | .vidioc_cropcap = vidioc_cropcap, | ||
1779 | .vidioc_g_crop = vidioc_g_crop, | ||
1780 | .vidioc_s_crop = vidioc_s_crop, | ||
1781 | .vidioc_g_jpegcomp = vidioc_g_jpegcomp, | ||
1782 | .vidioc_s_jpegcomp = vidioc_s_jpegcomp, | ||
1783 | }; | ||
1784 | |||
1785 | static struct video_device go7007_template = { | ||
1786 | .name = "go7007", | ||
1787 | .fops = &go7007_fops, | ||
1788 | .release = go7007_vfl_release, | ||
1789 | .ioctl_ops = &video_ioctl_ops, | ||
1790 | .tvnorms = V4L2_STD_ALL, | ||
1791 | .current_norm = V4L2_STD_NTSC, | ||
1792 | }; | ||
1793 | |||
1794 | int go7007_v4l2_init(struct go7007 *go) | ||
1795 | { | ||
1796 | int rv; | ||
1797 | |||
1798 | go->video_dev = video_device_alloc(); | ||
1799 | if (go->video_dev == NULL) | ||
1800 | return -ENOMEM; | ||
1801 | *go->video_dev = go7007_template; | ||
1802 | go->video_dev->parent = go->dev; | ||
1803 | rv = video_register_device(go->video_dev, VFL_TYPE_GRABBER, -1); | ||
1804 | if (rv < 0) { | ||
1805 | video_device_release(go->video_dev); | ||
1806 | go->video_dev = NULL; | ||
1807 | return rv; | ||
1808 | } | ||
1809 | rv = v4l2_device_register(go->dev, &go->v4l2_dev); | ||
1810 | if (rv < 0) { | ||
1811 | video_device_release(go->video_dev); | ||
1812 | go->video_dev = NULL; | ||
1813 | return rv; | ||
1814 | } | ||
1815 | video_set_drvdata(go->video_dev, go); | ||
1816 | ++go->ref_count; | ||
1817 | printk(KERN_INFO "%s: registered device %s [v4l2]\n", | ||
1818 | go->video_dev->name, video_device_node_name(go->video_dev)); | ||
1819 | |||
1820 | return 0; | ||
1821 | } | ||
1822 | |||
1823 | void go7007_v4l2_remove(struct go7007 *go) | ||
1824 | { | ||
1825 | unsigned long flags; | ||
1826 | |||
1827 | mutex_lock(&go->hw_lock); | ||
1828 | if (go->streaming) { | ||
1829 | go->streaming = 0; | ||
1830 | go7007_stream_stop(go); | ||
1831 | spin_lock_irqsave(&go->spinlock, flags); | ||
1832 | abort_queued(go); | ||
1833 | spin_unlock_irqrestore(&go->spinlock, flags); | ||
1834 | } | ||
1835 | mutex_unlock(&go->hw_lock); | ||
1836 | if (go->video_dev) | ||
1837 | video_unregister_device(go->video_dev); | ||
1838 | v4l2_device_unregister(&go->v4l2_dev); | ||
1839 | } | ||