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