blob: 06cacd37bbd801a014f35fb45614177441cafab8 [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
Greg Kroah-Hartman8fca1cb2008-11-13 15:35:08 -0800330#if 0
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800331static int clip_to_modet_map(struct go7007 *go, int region,
332 struct v4l2_clip *clip_list)
333{
334 struct v4l2_clip clip, *clip_ptr;
335 int x, y, mbnum;
336
337 /* Check if coordinates are OK and if any macroblocks are already
338 * used by other regions (besides 0) */
339 clip_ptr = clip_list;
340 while (clip_ptr) {
341 if (copy_from_user(&clip, clip_ptr, sizeof(clip)))
342 return -EFAULT;
343 if (clip.c.left < 0 || (clip.c.left & 0xF) ||
344 clip.c.width <= 0 || (clip.c.width & 0xF))
345 return -EINVAL;
346 if (clip.c.left + clip.c.width > go->width)
347 return -EINVAL;
348 if (clip.c.top < 0 || (clip.c.top & 0xF) ||
349 clip.c.height <= 0 || (clip.c.height & 0xF))
350 return -EINVAL;
351 if (clip.c.top + clip.c.height > go->height)
352 return -EINVAL;
353 for (y = 0; y < clip.c.height; y += 16)
354 for (x = 0; x < clip.c.width; x += 16) {
355 mbnum = (go->width >> 4) *
356 ((clip.c.top + y) >> 4) +
357 ((clip.c.left + x) >> 4);
358 if (go->modet_map[mbnum] != 0 &&
359 go->modet_map[mbnum] != region)
360 return -EBUSY;
361 }
362 clip_ptr = clip.next;
363 }
364
365 /* Clear old region macroblocks */
366 for (mbnum = 0; mbnum < 1624; ++mbnum)
367 if (go->modet_map[mbnum] == region)
368 go->modet_map[mbnum] = 0;
369
370 /* Claim macroblocks in this list */
371 clip_ptr = clip_list;
372 while (clip_ptr) {
373 if (copy_from_user(&clip, clip_ptr, sizeof(clip)))
374 return -EFAULT;
375 for (y = 0; y < clip.c.height; y += 16)
376 for (x = 0; x < clip.c.width; x += 16) {
377 mbnum = (go->width >> 4) *
378 ((clip.c.top + y) >> 4) +
379 ((clip.c.left + x) >> 4);
380 go->modet_map[mbnum] = region;
381 }
382 clip_ptr = clip.next;
383 }
384 return 0;
385}
386
Pete Eberleind73f8222008-10-30 12:56:33 -0700387static int mpeg_queryctrl(u32 id, struct v4l2_queryctrl *ctrl)
388{
389 static const u32 user_ctrls[] = {
390 V4L2_CID_USER_CLASS,
391 0
392 };
393 static const u32 mpeg_ctrls[] = {
394 V4L2_CID_MPEG_CLASS,
395 V4L2_CID_MPEG_STREAM_TYPE,
396 V4L2_CID_MPEG_VIDEO_ENCODING,
397 V4L2_CID_MPEG_VIDEO_ASPECT,
398 V4L2_CID_MPEG_VIDEO_GOP_SIZE,
399 V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
400 V4L2_CID_MPEG_VIDEO_BITRATE,
401 0
402 };
403 static const u32 *ctrl_classes[] = {
404 user_ctrls,
405 mpeg_ctrls,
406 NULL
407 };
408
409 /* The ctrl may already contain the queried i2c controls,
410 * query the mpeg controls if the existing ctrl id is
411 * greater than the next mpeg ctrl id.
412 */
413 id = v4l2_ctrl_next(ctrl_classes, id);
414 if (id >= ctrl->id && ctrl->name[0])
415 return 0;
416
417 memset(ctrl, 0, sizeof(*ctrl));
418 ctrl->id = id;
419
420 switch (ctrl->id) {
421 case V4L2_CID_USER_CLASS:
422 case V4L2_CID_MPEG_CLASS:
423 return v4l2_ctrl_query_fill_std(ctrl);
424 case V4L2_CID_MPEG_STREAM_TYPE:
425 return v4l2_ctrl_query_fill(ctrl,
426 V4L2_MPEG_STREAM_TYPE_MPEG2_DVD,
427 V4L2_MPEG_STREAM_TYPE_MPEG_ELEM, 1,
428 V4L2_MPEG_STREAM_TYPE_MPEG_ELEM);
429 case V4L2_CID_MPEG_VIDEO_ENCODING:
430 return v4l2_ctrl_query_fill(ctrl,
431 V4L2_MPEG_VIDEO_ENCODING_MPEG_1,
432 V4L2_MPEG_VIDEO_ENCODING_MPEG_4, 1,
433 V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
434 case V4L2_CID_MPEG_VIDEO_ASPECT:
435 return v4l2_ctrl_query_fill(ctrl,
436 V4L2_MPEG_VIDEO_ASPECT_1x1,
437 V4L2_MPEG_VIDEO_ASPECT_16x9, 1,
438 V4L2_MPEG_VIDEO_ASPECT_1x1);
439 case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
440 case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
441 return v4l2_ctrl_query_fill_std(ctrl);
442 case V4L2_CID_MPEG_VIDEO_BITRATE:
443 return v4l2_ctrl_query_fill(ctrl,
444 64000,
445 10000000, 1,
446 9800000);
447 default:
448 break;
449 }
450 return -EINVAL;
451}
452
453static int mpeg_s_control(struct v4l2_control *ctrl, struct go7007 *go)
454{
455 /* pretty sure we can't change any of these while streaming */
456 if (go->streaming)
457 return -EBUSY;
458
459 switch (ctrl->id) {
460 case V4L2_CID_MPEG_STREAM_TYPE:
461 switch (ctrl->value) {
462 case V4L2_MPEG_STREAM_TYPE_MPEG2_DVD:
463 go->format = GO7007_FORMAT_MPEG2;
464 go->bitrate = 9800000;
465 go->gop_size = 15;
466 go->pali = 0x48;
467 go->closed_gop = 1;
468 go->repeat_seqhead = 0;
469 go->seq_header_enable = 1;
470 go->gop_header_enable = 1;
471 go->dvd_mode = 1;
472 break;
473 case V4L2_MPEG_STREAM_TYPE_MPEG_ELEM:
474 /* todo: */
475 break;
476 default:
477 return -EINVAL;
478 }
479 break;
480 case V4L2_CID_MPEG_VIDEO_ENCODING:
481 switch (ctrl->value) {
482 case V4L2_MPEG_VIDEO_ENCODING_MPEG_1:
483 go->format = GO7007_FORMAT_MPEG1;
484 go->pali = 0;
485 break;
486 case V4L2_MPEG_VIDEO_ENCODING_MPEG_2:
487 go->format = GO7007_FORMAT_MPEG2;
488 /*if (mpeg->pali >> 24 == 2)
489 go->pali = mpeg->pali & 0xff;
490 else*/
491 go->pali = 0x48;
492 break;
493 case V4L2_MPEG_VIDEO_ENCODING_MPEG_4:
494 go->format = GO7007_FORMAT_MPEG4;
495 /*if (mpeg->pali >> 24 == 4)
496 go->pali = mpeg->pali & 0xff;
497 else*/
498 go->pali = 0xf5;
499 break;
500 default:
501 return -EINVAL;
502 }
503 go->gop_header_enable =
504 /*mpeg->flags & GO7007_MPEG_OMIT_GOP_HEADER
505 ? 0 :*/ 1;
506 /*if (mpeg->flags & GO7007_MPEG_REPEAT_SEQHEADER)
507 go->repeat_seqhead = 1;
508 else*/
509 go->repeat_seqhead = 0;
510 go->dvd_mode = 0;
511 break;
512 case V4L2_CID_MPEG_VIDEO_ASPECT:
513 if (go->format == GO7007_FORMAT_MJPEG)
514 return -EINVAL;
515 switch (ctrl->value) {
516 case V4L2_MPEG_VIDEO_ASPECT_1x1:
517 go->aspect_ratio = GO7007_RATIO_1_1;
518 break;
519 case V4L2_MPEG_VIDEO_ASPECT_4x3:
520 go->aspect_ratio = GO7007_RATIO_4_3;
521 break;
522 case V4L2_MPEG_VIDEO_ASPECT_16x9:
523 go->aspect_ratio = GO7007_RATIO_16_9;
524 break;
525 case V4L2_MPEG_VIDEO_ASPECT_221x100:
526 default:
527 return -EINVAL;
528 }
529 break;
530 case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
531 go->gop_size = ctrl->value;
532 break;
533 case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
534 if (ctrl->value != 0 && ctrl->value != 1)
535 return -EINVAL;
536 go->closed_gop = ctrl->value;
537 break;
538 case V4L2_CID_MPEG_VIDEO_BITRATE:
539 /* Upper bound is kind of arbitrary here */
540 if (ctrl->value < 64000 || ctrl->value > 10000000)
541 return -EINVAL;
542 go->bitrate = ctrl->value;
543 break;
544 default:
545 return -EINVAL;
546 }
547 return 0;
548}
549
550static int mpeg_g_control(struct v4l2_control *ctrl, struct go7007 *go)
551{
552 switch (ctrl->id) {
553 case V4L2_CID_MPEG_STREAM_TYPE:
554 if (go->dvd_mode)
555 ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG2_DVD;
556 else
557 ctrl->value = V4L2_MPEG_STREAM_TYPE_MPEG_ELEM;
558 break;
559 case V4L2_CID_MPEG_VIDEO_ENCODING:
560 switch (go->format) {
561 case GO7007_FORMAT_MPEG1:
562 ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
563 break;
564 case GO7007_FORMAT_MPEG2:
565 ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
566 break;
567 case GO7007_FORMAT_MPEG4:
568 ctrl->value = V4L2_MPEG_VIDEO_ENCODING_MPEG_4;
569 break;
570 default:
571 return -EINVAL;
572 }
573 break;
574 case V4L2_CID_MPEG_VIDEO_ASPECT:
575 switch (go->aspect_ratio) {
576 case GO7007_RATIO_1_1:
577 ctrl->value = V4L2_MPEG_VIDEO_ASPECT_1x1;
578 break;
579 case GO7007_RATIO_4_3:
580 ctrl->value = V4L2_MPEG_VIDEO_ASPECT_4x3;
581 break;
582 case GO7007_RATIO_16_9:
583 ctrl->value = V4L2_MPEG_VIDEO_ASPECT_16x9;
584 break;
585 default:
586 return -EINVAL;
587 }
588 break;
589 case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
590 ctrl->value = go->gop_size;
591 break;
592 case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
593 ctrl->value = go->closed_gop;
594 break;
595 case V4L2_CID_MPEG_VIDEO_BITRATE:
596 ctrl->value = go->bitrate;
597 break;
598 default:
599 return -EINVAL;
600 }
601 return 0;
602}
Greg Kroah-Hartman8fca1cb2008-11-13 15:35:08 -0800603#endif
Pete Eberleind73f8222008-10-30 12:56:33 -0700604
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -0200605static int vidioc_querycap(struct file *file, void *priv,
606 struct v4l2_capability *cap)
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800607{
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -0200608 struct go7007_file *gofh = priv;
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800609 struct go7007 *go = gofh->go;
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800610
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -0200611 strlcpy(cap->driver, "go7007", sizeof(cap->driver));
612 strlcpy(cap->card, go->name, sizeof(cap->card));
613#if 0
614 strlcpy(cap->bus_info, dev_name(&dev->udev->dev), sizeof(cap->bus_info));
615#endif
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800616
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -0200617 cap->version = KERNEL_VERSION(0, 9, 8);
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800618
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -0200619 cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
620 V4L2_CAP_STREAMING; /* | V4L2_CAP_AUDIO; */
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800621
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -0200622 if (go->board_info->flags & GO7007_BOARD_HAS_TUNER)
623 cap->capabilities |= V4L2_CAP_TUNER;
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800624
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -0200625 return 0;
626}
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800627
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -0200628static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
629 struct v4l2_fmtdesc *fmt)
630{
631 char *desc = NULL;
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800632
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -0200633 switch (fmt->index) {
634 case 0:
635 fmt->pixelformat = V4L2_PIX_FMT_MJPEG;
636 desc = "Motion-JPEG";
637 break;
638 case 1:
639 fmt->pixelformat = V4L2_PIX_FMT_MPEG;
640 desc = "MPEG1/MPEG2/MPEG4";
641 break;
642 default:
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800643 return -EINVAL;
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -0200644 }
645 fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
646 fmt->flags = V4L2_FMT_FLAG_COMPRESSED;
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800647
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -0200648 strncpy(fmt->description, desc, sizeof(fmt->description));
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800649
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -0200650 return 0;
651}
652
653static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
654 struct v4l2_format *fmt)
655{
656 struct go7007_file *gofh = priv;
657 struct go7007 *go = gofh->go;
658
659 fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
660 fmt->fmt.pix.width = go->width;
661 fmt->fmt.pix.height = go->height;
662 fmt->fmt.pix.pixelformat = (go->format == GO7007_FORMAT_MJPEG) ?
663 V4L2_PIX_FMT_MJPEG : V4L2_PIX_FMT_MPEG;
664 fmt->fmt.pix.field = V4L2_FIELD_NONE;
665 fmt->fmt.pix.bytesperline = 0;
666 fmt->fmt.pix.sizeimage = GO7007_BUF_SIZE;
667 fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
668
669 return 0;
670}
671
672static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
673 struct v4l2_format *fmt)
674{
675 struct go7007_file *gofh = priv;
676 struct go7007 *go = gofh->go;
677
678 return set_capture_size(go, fmt, 1);
679}
680
681static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
682 struct v4l2_format *fmt)
683{
684 struct go7007_file *gofh = priv;
685 struct go7007 *go = gofh->go;
686
687 if (go->streaming)
688 return -EBUSY;
689
690 return set_capture_size(go, fmt, 0);
691}
692
693static int vidioc_reqbufs(struct file *file, void *priv,
694 struct v4l2_requestbuffers *req)
695{
696 struct go7007_file *gofh = priv;
697 struct go7007 *go = gofh->go;
698 int retval = -EBUSY;
699 unsigned int count, i;
700
701 if (go->streaming)
702 return retval;
703
704 if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
705 req->memory != V4L2_MEMORY_MMAP)
706 return -EINVAL;
707
708 down(&gofh->lock);
709 for (i = 0; i < gofh->buf_count; ++i)
710 if (gofh->bufs[i].mapped > 0)
711 goto unlock_and_return;
712
713 down(&go->hw_lock);
714 if (go->in_use > 0 && gofh->buf_count == 0) {
715 up(&go->hw_lock);
716 goto unlock_and_return;
717 }
718
719 if (gofh->buf_count > 0)
720 kfree(gofh->bufs);
721
722 retval = -ENOMEM;
723 count = req->count;
724 if (count > 0) {
725 if (count < 2)
726 count = 2;
727 if (count > 32)
728 count = 32;
729
730 gofh->bufs = kmalloc(count * sizeof(struct go7007_buffer),
731 GFP_KERNEL);
732
733 if (!gofh->bufs) {
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800734 up(&go->hw_lock);
735 goto unlock_and_return;
736 }
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -0200737
738 memset(gofh->bufs, 0, count * sizeof(struct go7007_buffer));
739
740 for (i = 0; i < count; ++i) {
741 gofh->bufs[i].go = go;
742 gofh->bufs[i].index = i;
743 gofh->bufs[i].state = BUF_STATE_IDLE;
744 gofh->bufs[i].mapped = 0;
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800745 }
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -0200746
747 go->in_use = 1;
748 } else {
749 go->in_use = 0;
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800750 }
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800751
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -0200752 gofh->buf_count = count;
753 up(&go->hw_lock);
754 up(&gofh->lock);
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800755
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -0200756 memset(req, 0, sizeof(*req));
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800757
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -0200758 req->count = count;
759 req->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
760 req->memory = V4L2_MEMORY_MMAP;
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800761
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -0200762 return 0;
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800763
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -0200764unlock_and_return:
765 up(&gofh->lock);
766 return retval;
767}
768
769static int vidioc_querybuf(struct file *file, void *priv,
770 struct v4l2_buffer *buf)
771{
772 struct go7007_file *gofh = priv;
773 int retval = -EINVAL;
774 unsigned int index;
775
776 if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800777 return retval;
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800778
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -0200779 index = buf->index;
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800780
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -0200781 down(&gofh->lock);
782 if (index >= gofh->buf_count)
783 goto unlock_and_return;
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800784
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -0200785 memset(buf, 0, sizeof(*buf));
786 buf->index = index;
787 buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800788
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -0200789 switch (gofh->bufs[index].state) {
790 case BUF_STATE_QUEUED:
791 buf->flags = V4L2_BUF_FLAG_QUEUED;
792 break;
793 case BUF_STATE_DONE:
794 buf->flags = V4L2_BUF_FLAG_DONE;
795 break;
796 default:
797 buf->flags = 0;
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800798 }
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800799
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -0200800 if (gofh->bufs[index].mapped)
801 buf->flags |= V4L2_BUF_FLAG_MAPPED;
802 buf->memory = V4L2_MEMORY_MMAP;
803 buf->m.offset = index * GO7007_BUF_SIZE;
804 buf->length = GO7007_BUF_SIZE;
805 up(&gofh->lock);
806
807 return 0;
808
809unlock_and_return:
810 up(&gofh->lock);
811 return retval;
812}
813
814static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
815{
816 struct go7007_file *gofh = priv;
817 struct go7007 *go = gofh->go;
818 struct go7007_buffer *gobuf;
819 unsigned long flags;
820 int retval = -EINVAL;
821 int ret;
822
823 if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
824 buf->memory != V4L2_MEMORY_MMAP)
825 return retval;
826
827 down(&gofh->lock);
828 if (buf->index < 0 || buf->index >= gofh->buf_count)
829 goto unlock_and_return;
830
831 gobuf = &gofh->bufs[buf->index];
832 if (!gobuf->mapped)
833 goto unlock_and_return;
834
835 retval = -EBUSY;
836 if (gobuf->state != BUF_STATE_IDLE)
837 goto unlock_and_return;
838
839 /* offset will be 0 until we really support USERPTR streaming */
840 gobuf->offset = gobuf->user_addr & ~PAGE_MASK;
841 gobuf->bytesused = 0;
842 gobuf->frame_offset = 0;
843 gobuf->modet_active = 0;
844 if (gobuf->offset > 0)
845 gobuf->page_count = GO7007_BUF_PAGES + 1;
846 else
847 gobuf->page_count = GO7007_BUF_PAGES;
848
849 retval = -ENOMEM;
850 down_read(&current->mm->mmap_sem);
851 ret = get_user_pages(current, current->mm,
852 gobuf->user_addr & PAGE_MASK, gobuf->page_count,
853 1, 1, gobuf->pages, NULL);
854 up_read(&current->mm->mmap_sem);
855
856 if (ret != gobuf->page_count) {
857 int i;
858 for (i = 0; i < ret; ++i)
859 page_cache_release(gobuf->pages[i]);
860 gobuf->page_count = 0;
861 goto unlock_and_return;
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800862 }
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800863
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -0200864 gobuf->state = BUF_STATE_QUEUED;
865 spin_lock_irqsave(&go->spinlock, flags);
866 list_add_tail(&gobuf->stream, &go->stream);
867 spin_unlock_irqrestore(&go->spinlock, flags);
868 up(&gofh->lock);
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800869
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -0200870 return 0;
871
872unlock_and_return:
873 up(&gofh->lock);
874 return retval;
875}
876
877
878static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
879{
880 struct go7007_file *gofh = priv;
881 struct go7007 *go = gofh->go;
882 struct go7007_buffer *gobuf;
883 int retval = -EINVAL;
884 unsigned long flags;
885 u32 frame_type_flag;
886 DEFINE_WAIT(wait);
887
888 if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
889 return retval;
890 if (buf->memory != V4L2_MEMORY_MMAP)
891 return retval;
892
893 down(&gofh->lock);
894 if (list_empty(&go->stream))
895 goto unlock_and_return;
896 gobuf = list_entry(go->stream.next,
897 struct go7007_buffer, stream);
898
899 retval = -EAGAIN;
900 if (gobuf->state != BUF_STATE_DONE &&
901 !(file->f_flags & O_NONBLOCK)) {
902 for (;;) {
903 prepare_to_wait(&go->frame_waitq, &wait,
904 TASK_INTERRUPTIBLE);
905 if (gobuf->state == BUF_STATE_DONE)
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800906 break;
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -0200907 if (signal_pending(current)) {
908 retval = -ERESTARTSYS;
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800909 break;
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800910 }
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -0200911 schedule();
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800912 }
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -0200913 finish_wait(&go->frame_waitq, &wait);
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800914 }
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -0200915 if (gobuf->state != BUF_STATE_DONE)
916 goto unlock_and_return;
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800917
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -0200918 spin_lock_irqsave(&go->spinlock, flags);
919 deactivate_buffer(gobuf);
920 spin_unlock_irqrestore(&go->spinlock, flags);
921 frame_type_flag = get_frame_type_flag(gobuf, go->format);
922 gobuf->state = BUF_STATE_IDLE;
923
924 memset(buf, 0, sizeof(*buf));
925 buf->index = gobuf->index;
926 buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
927 buf->bytesused = gobuf->bytesused;
928 buf->flags = V4L2_BUF_FLAG_MAPPED | frame_type_flag;
929 buf->field = V4L2_FIELD_NONE;
930 buf->timestamp = gobuf->timestamp;
931 buf->sequence = gobuf->seq;
932 buf->memory = V4L2_MEMORY_MMAP;
933 buf->m.offset = gobuf->index * GO7007_BUF_SIZE;
934 buf->length = GO7007_BUF_SIZE;
935 buf->reserved = gobuf->modet_active;
936
937 up(&gofh->lock);
938 return 0;
939
940unlock_and_return:
941 up(&gofh->lock);
942 return retval;
943}
944
945static int vidioc_streamon(struct file *file, void *priv,
946 enum v4l2_buf_type type)
947{
948 struct go7007_file *gofh = priv;
949 struct go7007 *go = gofh->go;
950 int retval = 0;
951
952 if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
953 return -EINVAL;
954
955 down(&gofh->lock);
956 down(&go->hw_lock);
957
958 if (!go->streaming) {
959 go->streaming = 1;
960 go->next_seq = 0;
961 go->active_buf = NULL;
962 if (go7007_start_encoder(go) < 0)
963 retval = -EIO;
964 else
965 retval = 0;
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800966 }
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -0200967 up(&go->hw_lock);
968 up(&gofh->lock);
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -0800969
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -0200970 return retval;
971}
Pete Eberleind73f8222008-10-30 12:56:33 -0700972
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -0200973static int vidioc_streamoff(struct file *file, void *priv,
974 enum v4l2_buf_type type)
975{
976 struct go7007_file *gofh = priv;
977 struct go7007 *go = gofh->go;
978
979 if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
980 return -EINVAL;
981 down(&gofh->lock);
982 go7007_streamoff(go);
983 up(&gofh->lock);
984
985 return 0;
986}
987
988static int vidioc_queryctrl(struct file *file, void *priv,
989 struct v4l2_queryctrl *query)
990{
991 struct go7007_file *gofh = priv;
992 struct go7007 *go = gofh->go;
993
994 if (!go->i2c_adapter_online)
995 return -EIO;
996
997 i2c_clients_command(&go->i2c_adapter, VIDIOC_QUERYCTRL, query);
998
999 return (!query->name[0]) ? -EINVAL : 0;
1000}
1001
1002static int vidioc_g_ctrl(struct file *file, void *priv,
1003 struct v4l2_control *ctrl)
1004{
1005 struct go7007_file *gofh = priv;
1006 struct go7007 *go = gofh->go;
1007 struct v4l2_queryctrl query;
1008
1009 if (!go->i2c_adapter_online)
1010 return -EIO;
1011
1012 memset(&query, 0, sizeof(query));
1013 query.id = ctrl->id;
1014 i2c_clients_command(&go->i2c_adapter, VIDIOC_QUERYCTRL, &query);
1015 if (query.name[0] == 0)
1016 return -EINVAL;
1017 i2c_clients_command(&go->i2c_adapter, VIDIOC_G_CTRL, ctrl);
1018
1019 return 0;
1020}
1021
1022static int vidioc_s_ctrl(struct file *file, void *priv,
1023 struct v4l2_control *ctrl)
1024{
1025 struct go7007_file *gofh = priv;
1026 struct go7007 *go = gofh->go;
1027 struct v4l2_queryctrl query;
1028
1029 if (!go->i2c_adapter_online)
1030 return -EIO;
1031
1032 memset(&query, 0, sizeof(query));
1033 query.id = ctrl->id;
1034 i2c_clients_command(&go->i2c_adapter, VIDIOC_QUERYCTRL, &query);
1035 if (query.name[0] == 0)
1036 return -EINVAL;
1037 i2c_clients_command(&go->i2c_adapter, VIDIOC_S_CTRL, ctrl);
1038
1039 return 0;
1040}
1041
1042static int vidioc_g_parm(struct file *filp, void *priv,
1043 struct v4l2_streamparm *parm)
1044{
1045 struct go7007_file *gofh = priv;
1046 struct go7007 *go = gofh->go;
1047 struct v4l2_fract timeperframe = {
1048 .numerator = 1001 * go->fps_scale,
1049 .denominator = go->sensor_framerate,
1050 };
1051
1052 if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1053 return -EINVAL;
1054
1055 parm->parm.capture.capability |= V4L2_CAP_TIMEPERFRAME;
1056 parm->parm.capture.timeperframe = timeperframe;
1057
1058 return 0;
1059}
1060
1061static int vidioc_s_parm(struct file *filp, void *priv,
1062 struct v4l2_streamparm *parm)
1063{
1064 struct go7007_file *gofh = priv;
1065 struct go7007 *go = gofh->go;
1066 unsigned int n, d;
1067
1068 if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1069 return -EINVAL;
1070 if (parm->parm.capture.capturemode != 0)
1071 return -EINVAL;
1072
1073 n = go->sensor_framerate *
1074 parm->parm.capture.timeperframe.numerator;
1075 d = 1001 * parm->parm.capture.timeperframe.denominator;
1076 if (n != 0 && d != 0 && n > d)
1077 go->fps_scale = (n + d/2) / d;
1078 else
1079 go->fps_scale = 1;
1080
1081 return 0;
1082}
1083
1084/* VIDIOC_ENUMSTD on go7007 were used for enumberating the supported fps and
1085 its resolution, when the device is not connected to TV.
1086 This were an API abuse, probably used by the lack of specific IOCTL's to
1087 enumberate it, by the time the driver were written.
1088
1089 However, since kernel 2.6.19, two new ioctls (VIDIOC_ENUM_FRAMEINTERVALS
1090 and VIDIOC_ENUM_FRAMESIZES) were added for this purpose.
1091
1092 The two functions bellow implements the newer ioctls
1093*/
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -02001094static int vidioc_enum_framesizes(struct file *filp, void *priv,
1095 struct v4l2_frmsizeenum *fsize)
1096{
1097 struct go7007_file *gofh = priv;
1098 struct go7007 *go = gofh->go;
1099
1100 /* Return -EINVAL, if it is a TV board */
1101 if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) ||
1102 (go->board_info->sensor_flags & GO7007_SENSOR_TV))
1103 return -EINVAL;
1104
1105 if (fsize->index > 0)
1106 return -EINVAL;
1107
1108 fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
1109 fsize->discrete.width = go->board_info->sensor_width;
1110 fsize->discrete.height = go->board_info->sensor_height;
1111
1112 return 0;
1113}
1114
1115static int vidioc_enum_frameintervals(struct file *filp, void *priv,
1116 struct v4l2_frmivalenum *fival)
1117{
1118 struct go7007_file *gofh = priv;
1119 struct go7007 *go = gofh->go;
1120
1121 /* Return -EINVAL, if it is a TV board */
1122 if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) ||
1123 (go->board_info->sensor_flags & GO7007_SENSOR_TV))
1124 return -EINVAL;
1125
1126 if (fival->index > 0)
1127 return -EINVAL;
1128
1129 fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
1130 fival->discrete.numerator = 1001;
1131 fival->discrete.denominator = go->board_info->sensor_framerate;
1132
1133 return 0;
1134}
1135
1136static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *std)
1137{
1138 struct go7007_file *gofh = priv;
1139 struct go7007 *go = gofh->go;
1140
1141 if (go->streaming)
1142 return -EBUSY;
1143
1144 if (!(go->board_info->sensor_flags & GO7007_SENSOR_TV) &&
1145 *std != 0)
1146 return -EINVAL;
1147
1148 if (*std == 0)
1149 return -EINVAL;
1150
1151 if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) &&
1152 go->input == go->board_info->num_inputs - 1) {
1153 if (!go->i2c_adapter_online)
1154 return -EIO;
1155 i2c_clients_command(&go->i2c_adapter,
1156 VIDIOC_S_STD, std);
1157 if (!*std) /* hack to indicate EINVAL from tuner */
1158 return -EINVAL;
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -08001159 }
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -02001160
1161 if (*std & V4L2_STD_NTSC) {
1162 go->standard = GO7007_STD_NTSC;
1163 go->sensor_framerate = 30000;
1164 } else if (*std & V4L2_STD_PAL) {
1165 go->standard = GO7007_STD_PAL;
1166 go->sensor_framerate = 25025;
1167 } else if (*std & V4L2_STD_SECAM) {
1168 go->standard = GO7007_STD_PAL;
1169 go->sensor_framerate = 25025;
1170 } else
1171 return -EINVAL;
1172
1173 if (go->i2c_adapter_online)
1174 i2c_clients_command(&go->i2c_adapter,
1175 VIDIOC_S_STD, std);
1176 set_capture_size(go, NULL, 0);
1177
1178 return 0;
1179}
1180
1181#if 0
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -08001182 case VIDIOC_QUERYSTD:
1183 {
1184 v4l2_std_id *std = arg;
1185
1186 if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) &&
1187 go->input == go->board_info->num_inputs - 1) {
1188 if (!go->i2c_adapter_online)
1189 return -EIO;
1190 i2c_clients_command(&go->i2c_adapter,
1191 VIDIOC_QUERYSTD, arg);
1192 } else if (go->board_info->sensor_flags & GO7007_SENSOR_TV)
1193 *std = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM;
1194 else
1195 *std = 0;
1196 return 0;
1197 }
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -02001198#endif
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -08001199
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -02001200static int vidioc_enum_input(struct file *file, void *priv,
1201 struct v4l2_input *inp)
1202{
1203 struct go7007_file *gofh = priv;
1204 struct go7007 *go = gofh->go;
1205
1206 if (inp->index >= go->board_info->num_inputs)
1207 return -EINVAL;
1208
1209 strncpy(inp->name, go->board_info->inputs[inp->index].name,
1210 sizeof(inp->name));
1211
1212 /* If this board has a tuner, it will be the last input */
1213 if ((go->board_info->flags & GO7007_BOARD_HAS_TUNER) &&
1214 inp->index == go->board_info->num_inputs - 1)
1215 inp->type = V4L2_INPUT_TYPE_TUNER;
1216 else
1217 inp->type = V4L2_INPUT_TYPE_CAMERA;
1218
1219 inp->audioset = 0;
1220 inp->tuner = 0;
1221 if (go->board_info->sensor_flags & GO7007_SENSOR_TV)
1222 inp->std = V4L2_STD_NTSC | V4L2_STD_PAL |
1223 V4L2_STD_SECAM;
1224 else
1225 inp->std = 0;
1226
1227 return 0;
1228}
1229
1230
1231static int vidioc_g_input(struct file *file, void *priv, unsigned int *input)
1232{
1233 struct go7007_file *gofh = priv;
1234 struct go7007 *go = gofh->go;
1235
1236 *input = go->input;
1237
1238 return 0;
1239}
1240
1241static int vidioc_s_input(struct file *file, void *priv, unsigned int input)
1242{
1243 struct go7007_file *gofh = priv;
1244 struct go7007 *go = gofh->go;
1245
1246 if (input >= go->board_info->num_inputs)
1247 return -EINVAL;
1248 if (go->streaming)
1249 return -EBUSY;
1250
1251 go->input = input;
1252 if (go->i2c_adapter_online) {
1253 i2c_clients_command(&go->i2c_adapter, VIDIOC_S_INPUT,
1254 &go->board_info->inputs[input].video_input);
1255 i2c_clients_command(&go->i2c_adapter, VIDIOC_S_AUDIO,
1256 &go->board_info->inputs[input].audio_input);
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -08001257 }
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -08001258
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -02001259 return 0;
1260}
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -08001261
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -02001262static int vidioc_g_tuner(struct file *file, void *priv,
1263 struct v4l2_tuner *t)
1264{
1265 struct go7007_file *gofh = priv;
1266 struct go7007 *go = gofh->go;
1267
1268 if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER))
1269 return -EINVAL;
1270 if (t->index != 0)
1271 return -EINVAL;
1272 if (!go->i2c_adapter_online)
1273 return -EIO;
1274
1275 i2c_clients_command(&go->i2c_adapter, VIDIOC_G_TUNER, t);
1276
1277 t->index = 0;
1278 return 0;
1279}
1280
1281static int vidioc_s_tuner(struct file *file, void *priv,
1282 struct v4l2_tuner *t)
1283{
1284 struct go7007_file *gofh = priv;
1285 struct go7007 *go = gofh->go;
1286
1287 if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER))
1288 return -EINVAL;
1289 if (t->index != 0)
1290 return -EINVAL;
1291 if (!go->i2c_adapter_online)
1292 return -EIO;
1293
1294 switch (go->board_id) {
1295 case GO7007_BOARDID_PX_TV402U_NA:
1296 case GO7007_BOARDID_PX_TV402U_JP:
1297 /* No selectable options currently */
1298 if (t->audmode != V4L2_TUNER_MODE_STEREO)
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -08001299 return -EINVAL;
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -02001300 break;
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -08001301 }
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -08001302
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -02001303 i2c_clients_command(&go->i2c_adapter, VIDIOC_S_TUNER, t);
1304
1305 return 0;
1306}
1307
1308static int vidioc_g_frequency(struct file *file, void *priv,
1309 struct v4l2_frequency *f)
1310{
1311 struct go7007_file *gofh = priv;
1312 struct go7007 *go = gofh->go;
1313
1314 if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER))
1315 return -EINVAL;
1316 if (!go->i2c_adapter_online)
1317 return -EIO;
1318
1319 f->type = V4L2_TUNER_ANALOG_TV;
1320 i2c_clients_command(&go->i2c_adapter, VIDIOC_G_FREQUENCY, f);
1321 return 0;
1322}
1323
1324static int vidioc_s_frequency(struct file *file, void *priv,
1325 struct v4l2_frequency *f)
1326{
1327 struct go7007_file *gofh = priv;
1328 struct go7007 *go = gofh->go;
1329
1330 if (!(go->board_info->flags & GO7007_BOARD_HAS_TUNER))
1331 return -EINVAL;
1332 if (!go->i2c_adapter_online)
1333 return -EIO;
1334
1335 i2c_clients_command(&go->i2c_adapter, VIDIOC_S_FREQUENCY, f);
1336
1337 return 0;
1338}
1339
1340static int vidioc_cropcap(struct file *file, void *priv,
1341 struct v4l2_cropcap *cropcap)
1342{
1343 struct go7007_file *gofh = priv;
1344 struct go7007 *go = gofh->go;
1345
1346 if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1347 return -EINVAL;
1348
1349 /* These specify the raw input of the sensor */
1350 switch (go->standard) {
1351 case GO7007_STD_NTSC:
1352 cropcap->bounds.top = 0;
1353 cropcap->bounds.left = 0;
1354 cropcap->bounds.width = 720;
1355 cropcap->bounds.height = 480;
1356 cropcap->defrect.top = 0;
1357 cropcap->defrect.left = 0;
1358 cropcap->defrect.width = 720;
1359 cropcap->defrect.height = 480;
1360 break;
1361 case GO7007_STD_PAL:
1362 cropcap->bounds.top = 0;
1363 cropcap->bounds.left = 0;
1364 cropcap->bounds.width = 720;
1365 cropcap->bounds.height = 576;
1366 cropcap->defrect.top = 0;
1367 cropcap->defrect.left = 0;
1368 cropcap->defrect.width = 720;
1369 cropcap->defrect.height = 576;
1370 break;
1371 case GO7007_STD_OTHER:
1372 cropcap->bounds.top = 0;
1373 cropcap->bounds.left = 0;
1374 cropcap->bounds.width = go->board_info->sensor_width;
1375 cropcap->bounds.height = go->board_info->sensor_height;
1376 cropcap->defrect.top = 0;
1377 cropcap->defrect.left = 0;
1378 cropcap->defrect.width = go->board_info->sensor_width;
1379 cropcap->defrect.height = go->board_info->sensor_height;
1380 break;
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -08001381 }
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -08001382
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -02001383 return 0;
1384}
1385
1386static int vidioc_g_crop(struct file *file, void *priv, struct v4l2_crop *crop)
1387{
1388 struct go7007_file *gofh = priv;
1389 struct go7007 *go = gofh->go;
1390
1391 if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1392 return -EINVAL;
1393
1394 crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1395
1396 /* These specify the raw input of the sensor */
1397 switch (go->standard) {
1398 case GO7007_STD_NTSC:
1399 crop->c.top = 0;
1400 crop->c.left = 0;
1401 crop->c.width = 720;
1402 crop->c.height = 480;
1403 break;
1404 case GO7007_STD_PAL:
1405 crop->c.top = 0;
1406 crop->c.left = 0;
1407 crop->c.width = 720;
1408 crop->c.height = 576;
1409 break;
1410 case GO7007_STD_OTHER:
1411 crop->c.top = 0;
1412 crop->c.left = 0;
1413 crop->c.width = go->board_info->sensor_width;
1414 crop->c.height = go->board_info->sensor_height;
1415 break;
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -08001416 }
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -08001417
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -02001418 return 0;
1419}
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -08001420
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -02001421/* FIXME: vidioc_s_crop is not really implemented!!!
1422 */
1423static int vidioc_s_crop(struct file *file, void *priv, struct v4l2_crop *crop)
1424{
1425 if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1426 return -EINVAL;
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -08001427
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -02001428 return 0;
1429}
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -08001430
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -02001431static int vidioc_g_jpegcomp(struct file *file, void *priv,
1432 struct v4l2_jpegcompression *params)
1433{
1434 memset(params, 0, sizeof(*params));
1435 params->quality = 50; /* ?? */
1436 params->jpeg_markers = V4L2_JPEG_MARKER_DHT |
1437 V4L2_JPEG_MARKER_DQT;
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -08001438
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -02001439 return 0;
1440}
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -08001441
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -02001442static int vidioc_s_jpegcomp(struct file *file, void *priv,
1443 struct v4l2_jpegcompression *params)
1444{
1445 if (params->quality != 50 ||
1446 params->jpeg_markers != (V4L2_JPEG_MARKER_DHT |
1447 V4L2_JPEG_MARKER_DQT))
1448 return -EINVAL;
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -08001449
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -02001450 return 0;
1451}
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -08001452
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -02001453/* FIXME:
1454 Those ioctls are private, and not needed, since several standard
1455 extended controls already provide streaming control.
1456 So, those ioctls should be converted into vidioc_g_ext_ctrls()
1457 and vidioc_s_ext_ctrls()
1458 */
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -08001459
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -02001460#if 0
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -08001461 /* Temporary ioctls for controlling compression characteristics */
1462 case GO7007IOC_S_BITRATE:
1463 {
1464 int *bitrate = arg;
1465
1466 if (go->streaming)
1467 return -EINVAL;
1468 /* Upper bound is kind of arbitrary here */
1469 if (*bitrate < 64000 || *bitrate > 10000000)
1470 return -EINVAL;
1471 go->bitrate = *bitrate;
1472 return 0;
1473 }
1474 case GO7007IOC_G_BITRATE:
1475 {
1476 int *bitrate = arg;
1477
1478 *bitrate = go->bitrate;
1479 return 0;
1480 }
1481 case GO7007IOC_S_COMP_PARAMS:
1482 {
1483 struct go7007_comp_params *comp = arg;
1484
1485 if (go->format == GO7007_FORMAT_MJPEG)
1486 return -EINVAL;
1487 if (comp->gop_size > 0)
1488 go->gop_size = comp->gop_size;
1489 else
1490 go->gop_size = go->sensor_framerate / 1000;
1491 if (go->gop_size != 15)
1492 go->dvd_mode = 0;
1493 /*go->ipb = comp->max_b_frames > 0;*/ /* completely untested */
1494 if (go->board_info->sensor_flags & GO7007_SENSOR_TV) {
1495 switch (comp->aspect_ratio) {
1496 case GO7007_ASPECT_RATIO_4_3_NTSC:
1497 case GO7007_ASPECT_RATIO_4_3_PAL:
1498 go->aspect_ratio = GO7007_RATIO_4_3;
1499 break;
1500 case GO7007_ASPECT_RATIO_16_9_NTSC:
1501 case GO7007_ASPECT_RATIO_16_9_PAL:
1502 go->aspect_ratio = GO7007_RATIO_16_9;
1503 break;
1504 default:
1505 go->aspect_ratio = GO7007_RATIO_1_1;
1506 break;
1507 }
1508 }
1509 if (comp->flags & GO7007_COMP_OMIT_SEQ_HEADER) {
1510 go->dvd_mode = 0;
1511 go->seq_header_enable = 0;
1512 } else {
1513 go->seq_header_enable = 1;
1514 }
1515 /* fall-through */
1516 }
1517 case GO7007IOC_G_COMP_PARAMS:
1518 {
1519 struct go7007_comp_params *comp = arg;
1520
1521 if (go->format == GO7007_FORMAT_MJPEG)
1522 return -EINVAL;
1523 memset(comp, 0, sizeof(*comp));
1524 comp->gop_size = go->gop_size;
1525 comp->max_b_frames = go->ipb ? 2 : 0;
1526 switch (go->aspect_ratio) {
1527 case GO7007_RATIO_4_3:
1528 if (go->standard == GO7007_STD_NTSC)
1529 comp->aspect_ratio =
1530 GO7007_ASPECT_RATIO_4_3_NTSC;
1531 else
1532 comp->aspect_ratio =
1533 GO7007_ASPECT_RATIO_4_3_PAL;
1534 break;
1535 case GO7007_RATIO_16_9:
1536 if (go->standard == GO7007_STD_NTSC)
1537 comp->aspect_ratio =
1538 GO7007_ASPECT_RATIO_16_9_NTSC;
1539 else
1540 comp->aspect_ratio =
1541 GO7007_ASPECT_RATIO_16_9_PAL;
1542 break;
1543 default:
1544 comp->aspect_ratio = GO7007_ASPECT_RATIO_1_1;
1545 break;
1546 }
1547 if (go->closed_gop)
1548 comp->flags |= GO7007_COMP_CLOSED_GOP;
1549 if (!go->seq_header_enable)
1550 comp->flags |= GO7007_COMP_OMIT_SEQ_HEADER;
1551 return 0;
1552 }
1553 case GO7007IOC_S_MPEG_PARAMS:
1554 {
1555 struct go7007_mpeg_params *mpeg = arg;
1556
1557 if (go->format != GO7007_FORMAT_MPEG1 &&
1558 go->format != GO7007_FORMAT_MPEG2 &&
1559 go->format != GO7007_FORMAT_MPEG4)
1560 return -EINVAL;
1561
1562 if (mpeg->flags & GO7007_MPEG_FORCE_DVD_MODE) {
1563 go->format = GO7007_FORMAT_MPEG2;
1564 go->bitrate = 9800000;
1565 go->gop_size = 15;
1566 go->pali = 0x48;
1567 go->closed_gop = 1;
1568 go->repeat_seqhead = 0;
1569 go->seq_header_enable = 1;
1570 go->gop_header_enable = 1;
1571 go->dvd_mode = 1;
1572 } else {
1573 switch (mpeg->mpeg_video_standard) {
1574 case GO7007_MPEG_VIDEO_MPEG1:
1575 go->format = GO7007_FORMAT_MPEG1;
1576 go->pali = 0;
1577 break;
1578 case GO7007_MPEG_VIDEO_MPEG2:
1579 go->format = GO7007_FORMAT_MPEG2;
1580 if (mpeg->pali >> 24 == 2)
1581 go->pali = mpeg->pali & 0xff;
1582 else
1583 go->pali = 0x48;
1584 break;
1585 case GO7007_MPEG_VIDEO_MPEG4:
1586 go->format = GO7007_FORMAT_MPEG4;
1587 if (mpeg->pali >> 24 == 4)
1588 go->pali = mpeg->pali & 0xff;
1589 else
1590 go->pali = 0xf5;
1591 break;
1592 default:
1593 return -EINVAL;
1594 }
1595 go->gop_header_enable =
1596 mpeg->flags & GO7007_MPEG_OMIT_GOP_HEADER
1597 ? 0 : 1;
1598 if (mpeg->flags & GO7007_MPEG_REPEAT_SEQHEADER)
1599 go->repeat_seqhead = 1;
1600 else
1601 go->repeat_seqhead = 0;
1602 go->dvd_mode = 0;
1603 }
1604 /* fall-through */
1605 }
1606 case GO7007IOC_G_MPEG_PARAMS:
1607 {
1608 struct go7007_mpeg_params *mpeg = arg;
1609
1610 memset(mpeg, 0, sizeof(*mpeg));
1611 switch (go->format) {
1612 case GO7007_FORMAT_MPEG1:
1613 mpeg->mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG1;
1614 mpeg->pali = 0;
1615 break;
1616 case GO7007_FORMAT_MPEG2:
1617 mpeg->mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG2;
1618 mpeg->pali = GO7007_MPEG_PROFILE(2, go->pali);
1619 break;
1620 case GO7007_FORMAT_MPEG4:
1621 mpeg->mpeg_video_standard = GO7007_MPEG_VIDEO_MPEG4;
1622 mpeg->pali = GO7007_MPEG_PROFILE(4, go->pali);
1623 break;
1624 default:
1625 return -EINVAL;
1626 }
1627 if (!go->gop_header_enable)
1628 mpeg->flags |= GO7007_MPEG_OMIT_GOP_HEADER;
1629 if (go->repeat_seqhead)
1630 mpeg->flags |= GO7007_MPEG_REPEAT_SEQHEADER;
1631 if (go->dvd_mode)
1632 mpeg->flags |= GO7007_MPEG_FORCE_DVD_MODE;
1633 return 0;
1634 }
1635 case GO7007IOC_S_MD_PARAMS:
1636 {
1637 struct go7007_md_params *mdp = arg;
1638
1639 if (mdp->region > 3)
1640 return -EINVAL;
1641 if (mdp->trigger > 0) {
1642 go->modet[mdp->region].pixel_threshold =
1643 mdp->pixel_threshold >> 1;
1644 go->modet[mdp->region].motion_threshold =
1645 mdp->motion_threshold >> 1;
1646 go->modet[mdp->region].mb_threshold =
1647 mdp->trigger >> 1;
1648 go->modet[mdp->region].enable = 1;
1649 } else
1650 go->modet[mdp->region].enable = 0;
1651 /* fall-through */
1652 }
1653 case GO7007IOC_G_MD_PARAMS:
1654 {
1655 struct go7007_md_params *mdp = arg;
1656 int region = mdp->region;
1657
1658 if (mdp->region > 3)
1659 return -EINVAL;
1660 memset(mdp, 0, sizeof(struct go7007_md_params));
1661 mdp->region = region;
1662 if (!go->modet[region].enable)
1663 return 0;
1664 mdp->pixel_threshold =
1665 (go->modet[region].pixel_threshold << 1) + 1;
1666 mdp->motion_threshold =
1667 (go->modet[region].motion_threshold << 1) + 1;
1668 mdp->trigger =
1669 (go->modet[region].mb_threshold << 1) + 1;
1670 return 0;
1671 }
1672 case GO7007IOC_S_MD_REGION:
1673 {
1674 struct go7007_md_region *region = arg;
1675
1676 if (region->region < 1 || region->region > 3)
1677 return -EINVAL;
1678 return clip_to_modet_map(go, region->region, region->clips);
1679 }
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -02001680#endif
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -08001681
1682static ssize_t go7007_read(struct file *file, char __user *data,
1683 size_t count, loff_t *ppos)
1684{
1685 return -EINVAL;
1686}
1687
1688static void go7007_vm_open(struct vm_area_struct *vma)
1689{
1690 struct go7007_buffer *gobuf = vma->vm_private_data;
1691
1692 ++gobuf->mapped;
1693}
1694
1695static void go7007_vm_close(struct vm_area_struct *vma)
1696{
1697 struct go7007_buffer *gobuf = vma->vm_private_data;
1698 unsigned long flags;
1699
1700 if (--gobuf->mapped == 0) {
1701 spin_lock_irqsave(&gobuf->go->spinlock, flags);
1702 deactivate_buffer(gobuf);
1703 spin_unlock_irqrestore(&gobuf->go->spinlock, flags);
1704 }
1705}
1706
1707/* Copied from videobuf-dma-sg.c */
1708static int go7007_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
1709{
1710 struct page *page;
1711
1712 page = alloc_page(GFP_USER | __GFP_DMA32);
1713 if (!page)
1714 return VM_FAULT_OOM;
Guennadi Liakhovetskic0cd5012009-01-03 18:20:04 -03001715 clear_user_highpage(page, (unsigned long)vmf->virtual_address);
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -08001716 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,
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -02001819 .vidioc_enum_framesizes = vidioc_enum_framesizes,
1820 .vidioc_enum_frameintervals = vidioc_enum_frameintervals,
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -02001821 .vidioc_cropcap = vidioc_cropcap,
1822 .vidioc_g_crop = vidioc_g_crop,
1823 .vidioc_s_crop = vidioc_s_crop,
1824 .vidioc_g_jpegcomp = vidioc_g_jpegcomp,
1825 .vidioc_s_jpegcomp = vidioc_s_jpegcomp,
1826};
1827
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -08001828static struct video_device go7007_template = {
1829 .name = "go7007",
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -08001830 .fops = &go7007_fops,
1831 .minor = -1,
1832 .release = go7007_vfl_release,
Mauro Carvalho Chehab65f9f612008-11-11 22:54:30 -02001833 .ioctl_ops = &video_ioctl_ops,
1834 .tvnorms = V4L2_STD_ALL,
1835 .current_norm = V4L2_STD_NTSC,
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -08001836};
1837
1838int go7007_v4l2_init(struct go7007 *go)
1839{
1840 int rv;
1841
1842 go->video_dev = video_device_alloc();
1843 if (go->video_dev == NULL)
1844 return -ENOMEM;
1845 memcpy(go->video_dev, &go7007_template, sizeof(go7007_template));
1846 go->video_dev->parent = go->dev;
1847 rv = video_register_device(go->video_dev, VFL_TYPE_GRABBER, -1);
1848 if (rv < 0) {
1849 video_device_release(go->video_dev);
1850 go->video_dev = NULL;
1851 return rv;
1852 }
1853 video_set_drvdata(go->video_dev, go);
1854 ++go->ref_count;
Pete Eberleind73f8222008-10-30 12:56:33 -07001855 printk(KERN_INFO "%s: registered device video%d [v4l2]\n",
1856 go->video_dev->name, go->video_dev->num);
Greg Kroah-Hartman866b8692008-02-15 16:53:09 -08001857
1858 return 0;
1859}
1860
1861void go7007_v4l2_remove(struct go7007 *go)
1862{
1863 unsigned long flags;
1864
1865 down(&go->hw_lock);
1866 if (go->streaming) {
1867 go->streaming = 0;
1868 go7007_stream_stop(go);
1869 spin_lock_irqsave(&go->spinlock, flags);
1870 abort_queued(go);
1871 spin_unlock_irqrestore(&go->spinlock, flags);
1872 }
1873 up(&go->hw_lock);
1874 if (go->video_dev)
1875 video_unregister_device(go->video_dev);
1876}