diff options
-rw-r--r-- | drivers/media/common/saa7146_fops.c | 36 | ||||
-rw-r--r-- | drivers/media/common/saa7146_video.c | 1250 | ||||
-rw-r--r-- | drivers/media/dvb/ttpci/av7110_v4l.c | 479 | ||||
-rw-r--r-- | drivers/media/dvb/ttpci/budget-av.c | 88 | ||||
-rw-r--r-- | drivers/media/video/hexium_gemini.c | 292 | ||||
-rw-r--r-- | drivers/media/video/hexium_orion.c | 103 | ||||
-rw-r--r-- | drivers/media/video/mxb.c | 641 | ||||
-rw-r--r-- | include/media/saa7146_vv.h | 17 |
8 files changed, 1400 insertions, 1506 deletions
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c index cf06f4d10ad4..4a27d4eda628 100644 --- a/drivers/media/common/saa7146_fops.c +++ b/drivers/media/common/saa7146_fops.c | |||
@@ -308,14 +308,6 @@ static int fops_release(struct file *file) | |||
308 | return 0; | 308 | return 0; |
309 | } | 309 | } |
310 | 310 | ||
311 | static long fops_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
312 | { | ||
313 | /* | ||
314 | DEB_EE(("file:%p, cmd:%d, arg:%li\n", file, cmd, arg)); | ||
315 | */ | ||
316 | return video_usercopy(file, cmd, arg, saa7146_video_do_ioctl); | ||
317 | } | ||
318 | |||
319 | static int fops_mmap(struct file *file, struct vm_area_struct * vma) | 311 | static int fops_mmap(struct file *file, struct vm_area_struct * vma) |
320 | { | 312 | { |
321 | struct saa7146_fh *fh = file->private_data; | 313 | struct saa7146_fh *fh = file->private_data; |
@@ -425,7 +417,7 @@ static const struct v4l2_file_operations video_fops = | |||
425 | .write = fops_write, | 417 | .write = fops_write, |
426 | .poll = fops_poll, | 418 | .poll = fops_poll, |
427 | .mmap = fops_mmap, | 419 | .mmap = fops_mmap, |
428 | .ioctl = fops_ioctl, | 420 | .ioctl = video_ioctl2, |
429 | }; | 421 | }; |
430 | 422 | ||
431 | static void vv_callback(struct saa7146_dev *dev, unsigned long status) | 423 | static void vv_callback(struct saa7146_dev *dev, unsigned long status) |
@@ -452,19 +444,16 @@ static void vv_callback(struct saa7146_dev *dev, unsigned long status) | |||
452 | } | 444 | } |
453 | } | 445 | } |
454 | 446 | ||
455 | static struct video_device device_template = | ||
456 | { | ||
457 | .fops = &video_fops, | ||
458 | .minor = -1, | ||
459 | }; | ||
460 | |||
461 | int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv) | 447 | int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv) |
462 | { | 448 | { |
463 | struct saa7146_vv *vv = kzalloc (sizeof(struct saa7146_vv),GFP_KERNEL); | 449 | struct saa7146_vv *vv = kzalloc(sizeof(struct saa7146_vv), GFP_KERNEL); |
464 | if( NULL == vv ) { | 450 | |
451 | if (vv == NULL) { | ||
465 | ERR(("out of memory. aborting.\n")); | 452 | ERR(("out of memory. aborting.\n")); |
466 | return -1; | 453 | return -1; |
467 | } | 454 | } |
455 | ext_vv->ops = saa7146_video_ioctl_ops; | ||
456 | ext_vv->core_ops = &saa7146_video_ioctl_ops; | ||
468 | 457 | ||
469 | DEB_EE(("dev:%p\n",dev)); | 458 | DEB_EE(("dev:%p\n",dev)); |
470 | 459 | ||
@@ -521,6 +510,7 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev, | |||
521 | { | 510 | { |
522 | struct saa7146_vv *vv = dev->vv_data; | 511 | struct saa7146_vv *vv = dev->vv_data; |
523 | struct video_device *vfd; | 512 | struct video_device *vfd; |
513 | int err; | ||
524 | 514 | ||
525 | DEB_EE(("dev:%p, name:'%s', type:%d\n",dev,name,type)); | 515 | DEB_EE(("dev:%p, name:'%s', type:%d\n",dev,name,type)); |
526 | 516 | ||
@@ -529,16 +519,18 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev, | |||
529 | if (vfd == NULL) | 519 | if (vfd == NULL) |
530 | return -ENOMEM; | 520 | return -ENOMEM; |
531 | 521 | ||
532 | memcpy(vfd, &device_template, sizeof(struct video_device)); | 522 | vfd->fops = &video_fops; |
533 | strlcpy(vfd->name, name, sizeof(vfd->name)); | 523 | vfd->ioctl_ops = dev->ext_vv_data ? &dev->ext_vv_data->ops : |
524 | &saa7146_video_ioctl_ops; | ||
534 | vfd->release = video_device_release; | 525 | vfd->release = video_device_release; |
526 | strlcpy(vfd->name, name, sizeof(vfd->name)); | ||
535 | video_set_drvdata(vfd, dev); | 527 | video_set_drvdata(vfd, dev); |
536 | 528 | ||
537 | // fixme: -1 should be an insmod parameter *for the extension* (like "video_nr"); | 529 | err = video_register_device(vfd, type, -1); |
538 | if (video_register_device(vfd, type, -1) < 0) { | 530 | if (err < 0) { |
539 | ERR(("cannot register v4l2 device. skipping.\n")); | 531 | ERR(("cannot register v4l2 device. skipping.\n")); |
540 | video_device_release(vfd); | 532 | video_device_release(vfd); |
541 | return -1; | 533 | return err; |
542 | } | 534 | } |
543 | 535 | ||
544 | if( VFL_TYPE_GRABBER == type ) { | 536 | if( VFL_TYPE_GRABBER == type ) { |
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c index 47fee05eaefb..91b7a4def46c 100644 --- a/drivers/media/common/saa7146_video.c +++ b/drivers/media/common/saa7146_video.c | |||
@@ -97,172 +97,13 @@ struct saa7146_format* format_by_fourcc(struct saa7146_dev *dev, int fourcc) | |||
97 | return NULL; | 97 | return NULL; |
98 | } | 98 | } |
99 | 99 | ||
100 | static int g_fmt(struct saa7146_fh *fh, struct v4l2_format *f) | 100 | static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f); |
101 | { | ||
102 | struct saa7146_dev *dev = fh->dev; | ||
103 | DEB_EE(("dev:%p, fh:%p\n",dev,fh)); | ||
104 | |||
105 | switch (f->type) { | ||
106 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
107 | f->fmt.pix = fh->video_fmt; | ||
108 | return 0; | ||
109 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | ||
110 | f->fmt.win = fh->ov.win; | ||
111 | return 0; | ||
112 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
113 | { | ||
114 | f->fmt.vbi = fh->vbi_fmt; | ||
115 | return 0; | ||
116 | } | ||
117 | default: | ||
118 | DEB_D(("invalid format type '%d'.\n",f->type)); | ||
119 | return -EINVAL; | ||
120 | } | ||
121 | } | ||
122 | |||
123 | static int try_win(struct saa7146_dev *dev, struct v4l2_window *win) | ||
124 | { | ||
125 | struct saa7146_vv *vv = dev->vv_data; | ||
126 | enum v4l2_field field; | ||
127 | int maxw, maxh; | ||
128 | |||
129 | DEB_EE(("dev:%p\n",dev)); | ||
130 | |||
131 | if (NULL == vv->ov_fb.base) { | ||
132 | DEB_D(("no fb base set.\n")); | ||
133 | return -EINVAL; | ||
134 | } | ||
135 | if (NULL == vv->ov_fmt) { | ||
136 | DEB_D(("no fb fmt set.\n")); | ||
137 | return -EINVAL; | ||
138 | } | ||
139 | if (win->w.width < 48 || win->w.height < 32) { | ||
140 | DEB_D(("min width/height. (%d,%d)\n",win->w.width,win->w.height)); | ||
141 | return -EINVAL; | ||
142 | } | ||
143 | if (win->clipcount > 16) { | ||
144 | DEB_D(("clipcount too big.\n")); | ||
145 | return -EINVAL; | ||
146 | } | ||
147 | |||
148 | field = win->field; | ||
149 | maxw = vv->standard->h_max_out; | ||
150 | maxh = vv->standard->v_max_out; | ||
151 | |||
152 | if (V4L2_FIELD_ANY == field) { | ||
153 | field = (win->w.height > maxh/2) | ||
154 | ? V4L2_FIELD_INTERLACED | ||
155 | : V4L2_FIELD_TOP; | ||
156 | } | ||
157 | switch (field) { | ||
158 | case V4L2_FIELD_TOP: | ||
159 | case V4L2_FIELD_BOTTOM: | ||
160 | case V4L2_FIELD_ALTERNATE: | ||
161 | maxh = maxh / 2; | ||
162 | break; | ||
163 | case V4L2_FIELD_INTERLACED: | ||
164 | break; | ||
165 | default: { | ||
166 | DEB_D(("no known field mode '%d'.\n",field)); | ||
167 | return -EINVAL; | ||
168 | } | ||
169 | } | ||
170 | |||
171 | win->field = field; | ||
172 | if (win->w.width > maxw) | ||
173 | win->w.width = maxw; | ||
174 | if (win->w.height > maxh) | ||
175 | win->w.height = maxh; | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | static int try_fmt(struct saa7146_fh *fh, struct v4l2_format *f) | ||
181 | { | ||
182 | struct saa7146_dev *dev = fh->dev; | ||
183 | struct saa7146_vv *vv = dev->vv_data; | ||
184 | int err; | ||
185 | |||
186 | switch (f->type) { | ||
187 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
188 | { | ||
189 | struct saa7146_format *fmt; | ||
190 | enum v4l2_field field; | ||
191 | int maxw, maxh; | ||
192 | int calc_bpl; | ||
193 | |||
194 | DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n",dev,fh)); | ||
195 | |||
196 | fmt = format_by_fourcc(dev,f->fmt.pix.pixelformat); | ||
197 | if (NULL == fmt) { | ||
198 | return -EINVAL; | ||
199 | } | ||
200 | |||
201 | field = f->fmt.pix.field; | ||
202 | maxw = vv->standard->h_max_out; | ||
203 | maxh = vv->standard->v_max_out; | ||
204 | |||
205 | if (V4L2_FIELD_ANY == field) { | ||
206 | field = (f->fmt.pix.height > maxh/2) | ||
207 | ? V4L2_FIELD_INTERLACED | ||
208 | : V4L2_FIELD_BOTTOM; | ||
209 | } | ||
210 | switch (field) { | ||
211 | case V4L2_FIELD_ALTERNATE: { | ||
212 | vv->last_field = V4L2_FIELD_TOP; | ||
213 | maxh = maxh / 2; | ||
214 | break; | ||
215 | } | ||
216 | case V4L2_FIELD_TOP: | ||
217 | case V4L2_FIELD_BOTTOM: | ||
218 | vv->last_field = V4L2_FIELD_INTERLACED; | ||
219 | maxh = maxh / 2; | ||
220 | break; | ||
221 | case V4L2_FIELD_INTERLACED: | ||
222 | vv->last_field = V4L2_FIELD_INTERLACED; | ||
223 | break; | ||
224 | default: { | ||
225 | DEB_D(("no known field mode '%d'.\n",field)); | ||
226 | return -EINVAL; | ||
227 | } | ||
228 | } | ||
229 | |||
230 | f->fmt.pix.field = field; | ||
231 | if (f->fmt.pix.width > maxw) | ||
232 | f->fmt.pix.width = maxw; | ||
233 | if (f->fmt.pix.height > maxh) | ||
234 | f->fmt.pix.height = maxh; | ||
235 | |||
236 | calc_bpl = (f->fmt.pix.width * fmt->depth)/8; | ||
237 | |||
238 | if (f->fmt.pix.bytesperline < calc_bpl) | ||
239 | f->fmt.pix.bytesperline = calc_bpl; | ||
240 | |||
241 | if (f->fmt.pix.bytesperline > (2*PAGE_SIZE * fmt->depth)/8) /* arbitrary constraint */ | ||
242 | f->fmt.pix.bytesperline = calc_bpl; | ||
243 | |||
244 | f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; | ||
245 | DEB_D(("w:%d, h:%d, bytesperline:%d, sizeimage:%d\n",f->fmt.pix.width,f->fmt.pix.height,f->fmt.pix.bytesperline,f->fmt.pix.sizeimage)); | ||
246 | |||
247 | return 0; | ||
248 | } | ||
249 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | ||
250 | DEB_EE(("V4L2_BUF_TYPE_VIDEO_OVERLAY: dev:%p, fh:%p\n",dev,fh)); | ||
251 | err = try_win(dev,&f->fmt.win); | ||
252 | if (0 != err) { | ||
253 | return err; | ||
254 | } | ||
255 | return 0; | ||
256 | default: | ||
257 | DEB_EE(("unknown format type '%d'\n",f->type)); | ||
258 | return -EINVAL; | ||
259 | } | ||
260 | } | ||
261 | 101 | ||
262 | int saa7146_start_preview(struct saa7146_fh *fh) | 102 | int saa7146_start_preview(struct saa7146_fh *fh) |
263 | { | 103 | { |
264 | struct saa7146_dev *dev = fh->dev; | 104 | struct saa7146_dev *dev = fh->dev; |
265 | struct saa7146_vv *vv = dev->vv_data; | 105 | struct saa7146_vv *vv = dev->vv_data; |
106 | struct v4l2_format fmt; | ||
266 | int ret = 0, err = 0; | 107 | int ret = 0, err = 0; |
267 | 108 | ||
268 | DEB_EE(("dev:%p, fh:%p\n",dev,fh)); | 109 | DEB_EE(("dev:%p, fh:%p\n",dev,fh)); |
@@ -294,12 +135,13 @@ int saa7146_start_preview(struct saa7146_fh *fh) | |||
294 | return -EBUSY; | 135 | return -EBUSY; |
295 | } | 136 | } |
296 | 137 | ||
297 | err = try_win(dev,&fh->ov.win); | 138 | fmt.fmt.win = fh->ov.win; |
139 | err = vidioc_try_fmt_vid_overlay(NULL, fh, &fmt); | ||
298 | if (0 != err) { | 140 | if (0 != err) { |
299 | saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP); | 141 | saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP); |
300 | return -EBUSY; | 142 | return -EBUSY; |
301 | } | 143 | } |
302 | 144 | fh->ov.win = fmt.fmt.win; | |
303 | vv->ov_data = &fh->ov; | 145 | vv->ov_data = &fh->ov; |
304 | 146 | ||
305 | DEB_D(("%dx%d+%d+%d %s field=%s\n", | 147 | DEB_D(("%dx%d+%d+%d %s field=%s\n", |
@@ -355,58 +197,6 @@ int saa7146_stop_preview(struct saa7146_fh *fh) | |||
355 | } | 197 | } |
356 | EXPORT_SYMBOL_GPL(saa7146_stop_preview); | 198 | EXPORT_SYMBOL_GPL(saa7146_stop_preview); |
357 | 199 | ||
358 | static int s_fmt(struct saa7146_fh *fh, struct v4l2_format *f) | ||
359 | { | ||
360 | struct saa7146_dev *dev = fh->dev; | ||
361 | struct saa7146_vv *vv = dev->vv_data; | ||
362 | |||
363 | int err; | ||
364 | |||
365 | switch (f->type) { | ||
366 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
367 | DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n",dev,fh)); | ||
368 | if (IS_CAPTURE_ACTIVE(fh) != 0) { | ||
369 | DEB_EE(("streaming capture is active\n")); | ||
370 | return -EBUSY; | ||
371 | } | ||
372 | err = try_fmt(fh,f); | ||
373 | if (0 != err) | ||
374 | return err; | ||
375 | fh->video_fmt = f->fmt.pix; | ||
376 | DEB_EE(("set to pixelformat '%4.4s'\n",(char *)&fh->video_fmt.pixelformat)); | ||
377 | return 0; | ||
378 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | ||
379 | DEB_EE(("V4L2_BUF_TYPE_VIDEO_OVERLAY: dev:%p, fh:%p\n",dev,fh)); | ||
380 | err = try_win(dev,&f->fmt.win); | ||
381 | if (0 != err) | ||
382 | return err; | ||
383 | mutex_lock(&dev->lock); | ||
384 | fh->ov.win = f->fmt.win; | ||
385 | fh->ov.nclips = f->fmt.win.clipcount; | ||
386 | if (fh->ov.nclips > 16) | ||
387 | fh->ov.nclips = 16; | ||
388 | if (copy_from_user(fh->ov.clips,f->fmt.win.clips,sizeof(struct v4l2_clip)*fh->ov.nclips)) { | ||
389 | mutex_unlock(&dev->lock); | ||
390 | return -EFAULT; | ||
391 | } | ||
392 | |||
393 | /* fh->ov.fh is used to indicate that we have valid overlay informations, too */ | ||
394 | fh->ov.fh = fh; | ||
395 | |||
396 | mutex_unlock(&dev->lock); | ||
397 | |||
398 | /* check if our current overlay is active */ | ||
399 | if (IS_OVERLAY_ACTIVE(fh) != 0) { | ||
400 | saa7146_stop_preview(fh); | ||
401 | saa7146_start_preview(fh); | ||
402 | } | ||
403 | return 0; | ||
404 | default: | ||
405 | DEB_D(("unknown format type '%d'\n",f->type)); | ||
406 | return -EINVAL; | ||
407 | } | ||
408 | } | ||
409 | |||
410 | /********************************************************************************/ | 200 | /********************************************************************************/ |
411 | /* device controls */ | 201 | /* device controls */ |
412 | 202 | ||
@@ -463,132 +253,6 @@ static struct v4l2_queryctrl* ctrl_by_id(int id) | |||
463 | return NULL; | 253 | return NULL; |
464 | } | 254 | } |
465 | 255 | ||
466 | static int get_control(struct saa7146_fh *fh, struct v4l2_control *c) | ||
467 | { | ||
468 | struct saa7146_dev *dev = fh->dev; | ||
469 | struct saa7146_vv *vv = dev->vv_data; | ||
470 | |||
471 | const struct v4l2_queryctrl* ctrl; | ||
472 | u32 value = 0; | ||
473 | |||
474 | ctrl = ctrl_by_id(c->id); | ||
475 | if (NULL == ctrl) | ||
476 | return -EINVAL; | ||
477 | switch (c->id) { | ||
478 | case V4L2_CID_BRIGHTNESS: | ||
479 | value = saa7146_read(dev, BCS_CTRL); | ||
480 | c->value = 0xff & (value >> 24); | ||
481 | DEB_D(("V4L2_CID_BRIGHTNESS: %d\n",c->value)); | ||
482 | break; | ||
483 | case V4L2_CID_CONTRAST: | ||
484 | value = saa7146_read(dev, BCS_CTRL); | ||
485 | c->value = 0x7f & (value >> 16); | ||
486 | DEB_D(("V4L2_CID_CONTRAST: %d\n",c->value)); | ||
487 | break; | ||
488 | case V4L2_CID_SATURATION: | ||
489 | value = saa7146_read(dev, BCS_CTRL); | ||
490 | c->value = 0x7f & (value >> 0); | ||
491 | DEB_D(("V4L2_CID_SATURATION: %d\n",c->value)); | ||
492 | break; | ||
493 | case V4L2_CID_VFLIP: | ||
494 | c->value = vv->vflip; | ||
495 | DEB_D(("V4L2_CID_VFLIP: %d\n",c->value)); | ||
496 | break; | ||
497 | case V4L2_CID_HFLIP: | ||
498 | c->value = vv->hflip; | ||
499 | DEB_D(("V4L2_CID_HFLIP: %d\n",c->value)); | ||
500 | break; | ||
501 | default: | ||
502 | return -EINVAL; | ||
503 | } | ||
504 | |||
505 | return 0; | ||
506 | } | ||
507 | |||
508 | static int set_control(struct saa7146_fh *fh, struct v4l2_control *c) | ||
509 | { | ||
510 | struct saa7146_dev *dev = fh->dev; | ||
511 | struct saa7146_vv *vv = dev->vv_data; | ||
512 | |||
513 | const struct v4l2_queryctrl* ctrl; | ||
514 | |||
515 | ctrl = ctrl_by_id(c->id); | ||
516 | if (NULL == ctrl) { | ||
517 | DEB_D(("unknown control %d\n",c->id)); | ||
518 | return -EINVAL; | ||
519 | } | ||
520 | |||
521 | mutex_lock(&dev->lock); | ||
522 | |||
523 | switch (ctrl->type) { | ||
524 | case V4L2_CTRL_TYPE_BOOLEAN: | ||
525 | case V4L2_CTRL_TYPE_MENU: | ||
526 | case V4L2_CTRL_TYPE_INTEGER: | ||
527 | if (c->value < ctrl->minimum) | ||
528 | c->value = ctrl->minimum; | ||
529 | if (c->value > ctrl->maximum) | ||
530 | c->value = ctrl->maximum; | ||
531 | break; | ||
532 | default: | ||
533 | /* nothing */; | ||
534 | }; | ||
535 | |||
536 | switch (c->id) { | ||
537 | case V4L2_CID_BRIGHTNESS: { | ||
538 | u32 value = saa7146_read(dev, BCS_CTRL); | ||
539 | value &= 0x00ffffff; | ||
540 | value |= (c->value << 24); | ||
541 | saa7146_write(dev, BCS_CTRL, value); | ||
542 | saa7146_write(dev, MC2, MASK_22 | MASK_06 ); | ||
543 | break; | ||
544 | } | ||
545 | case V4L2_CID_CONTRAST: { | ||
546 | u32 value = saa7146_read(dev, BCS_CTRL); | ||
547 | value &= 0xff00ffff; | ||
548 | value |= (c->value << 16); | ||
549 | saa7146_write(dev, BCS_CTRL, value); | ||
550 | saa7146_write(dev, MC2, MASK_22 | MASK_06 ); | ||
551 | break; | ||
552 | } | ||
553 | case V4L2_CID_SATURATION: { | ||
554 | u32 value = saa7146_read(dev, BCS_CTRL); | ||
555 | value &= 0xffffff00; | ||
556 | value |= (c->value << 0); | ||
557 | saa7146_write(dev, BCS_CTRL, value); | ||
558 | saa7146_write(dev, MC2, MASK_22 | MASK_06 ); | ||
559 | break; | ||
560 | } | ||
561 | case V4L2_CID_HFLIP: | ||
562 | /* fixme: we can support changing VFLIP and HFLIP here... */ | ||
563 | if (IS_CAPTURE_ACTIVE(fh) != 0) { | ||
564 | DEB_D(("V4L2_CID_HFLIP while active capture.\n")); | ||
565 | mutex_unlock(&dev->lock); | ||
566 | return -EINVAL; | ||
567 | } | ||
568 | vv->hflip = c->value; | ||
569 | break; | ||
570 | case V4L2_CID_VFLIP: | ||
571 | if (IS_CAPTURE_ACTIVE(fh) != 0) { | ||
572 | DEB_D(("V4L2_CID_VFLIP while active capture.\n")); | ||
573 | mutex_unlock(&dev->lock); | ||
574 | return -EINVAL; | ||
575 | } | ||
576 | vv->vflip = c->value; | ||
577 | break; | ||
578 | default: { | ||
579 | mutex_unlock(&dev->lock); | ||
580 | return -EINVAL; | ||
581 | } | ||
582 | } | ||
583 | mutex_unlock(&dev->lock); | ||
584 | |||
585 | if (IS_OVERLAY_ACTIVE(fh) != 0) { | ||
586 | saa7146_stop_preview(fh); | ||
587 | saa7146_start_preview(fh); | ||
588 | } | ||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | /********************************************************************************/ | 256 | /********************************************************************************/ |
593 | /* common pagetable functions */ | 257 | /* common pagetable functions */ |
594 | 258 | ||
@@ -829,231 +493,451 @@ static int video_end(struct saa7146_fh *fh, struct file *file) | |||
829 | return 0; | 493 | return 0; |
830 | } | 494 | } |
831 | 495 | ||
832 | /* | 496 | static int vidioc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) |
833 | * This function is _not_ called directly, but from | 497 | { |
834 | * video_generic_ioctl (and maybe others). userspace | 498 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; |
835 | * copying is done already, arg is a kernel pointer. | 499 | |
836 | */ | 500 | strcpy((char *)cap->driver, "saa7146 v4l2"); |
501 | strlcpy((char *)cap->card, dev->ext->name, sizeof(cap->card)); | ||
502 | sprintf((char *)cap->bus_info, "PCI:%s", pci_name(dev->pci)); | ||
503 | cap->version = SAA7146_VERSION_CODE; | ||
504 | cap->capabilities = | ||
505 | V4L2_CAP_VIDEO_CAPTURE | | ||
506 | V4L2_CAP_VIDEO_OVERLAY | | ||
507 | V4L2_CAP_READWRITE | | ||
508 | V4L2_CAP_STREAMING; | ||
509 | cap->capabilities |= dev->ext_vv_data->capabilities; | ||
510 | return 0; | ||
511 | } | ||
837 | 512 | ||
838 | long saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg) | 513 | static int vidioc_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb) |
839 | { | 514 | { |
840 | struct saa7146_fh *fh = file->private_data; | 515 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; |
841 | struct saa7146_dev *dev = fh->dev; | ||
842 | struct saa7146_vv *vv = dev->vv_data; | 516 | struct saa7146_vv *vv = dev->vv_data; |
843 | 517 | ||
844 | long err = 0; | 518 | *fb = vv->ov_fb; |
845 | int result = 0, ee = 0; | 519 | fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; |
520 | return 0; | ||
521 | } | ||
522 | |||
523 | static int vidioc_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb) | ||
524 | { | ||
525 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
526 | struct saa7146_vv *vv = dev->vv_data; | ||
527 | struct saa7146_format *fmt; | ||
846 | 528 | ||
847 | struct saa7146_use_ops *ops; | 529 | DEB_EE(("VIDIOC_S_FBUF\n")); |
848 | struct videobuf_queue *q; | ||
849 | 530 | ||
850 | /* check if extension handles the command */ | 531 | if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO)) |
851 | for(ee = 0; dev->ext_vv_data->ioctls[ee].flags != 0; ee++) { | 532 | return -EPERM; |
852 | if( cmd == dev->ext_vv_data->ioctls[ee].cmd ) | 533 | |
853 | break; | 534 | /* check args */ |
535 | fmt = format_by_fourcc(dev, fb->fmt.pixelformat); | ||
536 | if (NULL == fmt) | ||
537 | return -EINVAL; | ||
538 | |||
539 | /* planar formats are not allowed for overlay video, clipping and video dma would clash */ | ||
540 | if (fmt->flags & FORMAT_IS_PLANAR) | ||
541 | DEB_S(("planar pixelformat '%4.4s' not allowed for overlay\n", | ||
542 | (char *)&fmt->pixelformat)); | ||
543 | |||
544 | /* check if overlay is running */ | ||
545 | if (IS_OVERLAY_ACTIVE(fh) != 0) { | ||
546 | if (vv->video_fh != fh) { | ||
547 | DEB_D(("refusing to change framebuffer informations while overlay is active in another open.\n")); | ||
548 | return -EBUSY; | ||
549 | } | ||
854 | } | 550 | } |
855 | 551 | ||
856 | if( 0 != (dev->ext_vv_data->ioctls[ee].flags & SAA7146_EXCLUSIVE) ) { | 552 | mutex_lock(&dev->lock); |
857 | DEB_D(("extension handles ioctl exclusive.\n")); | 553 | |
858 | result = dev->ext_vv_data->ioctl(fh, cmd, arg); | 554 | /* ok, accept it */ |
859 | return result; | 555 | vv->ov_fb = *fb; |
556 | vv->ov_fmt = fmt; | ||
557 | if (0 == vv->ov_fb.fmt.bytesperline) | ||
558 | vv->ov_fb.fmt.bytesperline = | ||
559 | vv->ov_fb.fmt.width * fmt->depth / 8; | ||
560 | |||
561 | mutex_unlock(&dev->lock); | ||
562 | return 0; | ||
563 | } | ||
564 | |||
565 | static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) | ||
566 | { | ||
567 | if (f->index >= NUM_FORMATS) | ||
568 | return -EINVAL; | ||
569 | strlcpy((char *)f->description, formats[f->index].name, | ||
570 | sizeof(f->description)); | ||
571 | f->pixelformat = formats[f->index].pixelformat; | ||
572 | return 0; | ||
573 | } | ||
574 | |||
575 | static int vidioc_enum_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_fmtdesc *f) | ||
576 | { | ||
577 | return vidioc_enum_fmt_vid_cap(file, fh, f); | ||
578 | } | ||
579 | |||
580 | static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c) | ||
581 | { | ||
582 | const struct v4l2_queryctrl *ctrl; | ||
583 | |||
584 | if ((c->id < V4L2_CID_BASE || | ||
585 | c->id >= V4L2_CID_LASTP1) && | ||
586 | (c->id < V4L2_CID_PRIVATE_BASE || | ||
587 | c->id >= V4L2_CID_PRIVATE_LASTP1)) | ||
588 | return -EINVAL; | ||
589 | |||
590 | ctrl = ctrl_by_id(c->id); | ||
591 | if (ctrl == NULL) | ||
592 | return -EINVAL; | ||
593 | |||
594 | DEB_EE(("VIDIOC_QUERYCTRL: id:%d\n", c->id)); | ||
595 | *c = *ctrl; | ||
596 | return 0; | ||
597 | } | ||
598 | |||
599 | static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c) | ||
600 | { | ||
601 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
602 | struct saa7146_vv *vv = dev->vv_data; | ||
603 | const struct v4l2_queryctrl *ctrl; | ||
604 | u32 value = 0; | ||
605 | |||
606 | ctrl = ctrl_by_id(c->id); | ||
607 | if (NULL == ctrl) | ||
608 | return -EINVAL; | ||
609 | switch (c->id) { | ||
610 | case V4L2_CID_BRIGHTNESS: | ||
611 | value = saa7146_read(dev, BCS_CTRL); | ||
612 | c->value = 0xff & (value >> 24); | ||
613 | DEB_D(("V4L2_CID_BRIGHTNESS: %d\n", c->value)); | ||
614 | break; | ||
615 | case V4L2_CID_CONTRAST: | ||
616 | value = saa7146_read(dev, BCS_CTRL); | ||
617 | c->value = 0x7f & (value >> 16); | ||
618 | DEB_D(("V4L2_CID_CONTRAST: %d\n", c->value)); | ||
619 | break; | ||
620 | case V4L2_CID_SATURATION: | ||
621 | value = saa7146_read(dev, BCS_CTRL); | ||
622 | c->value = 0x7f & (value >> 0); | ||
623 | DEB_D(("V4L2_CID_SATURATION: %d\n", c->value)); | ||
624 | break; | ||
625 | case V4L2_CID_VFLIP: | ||
626 | c->value = vv->vflip; | ||
627 | DEB_D(("V4L2_CID_VFLIP: %d\n", c->value)); | ||
628 | break; | ||
629 | case V4L2_CID_HFLIP: | ||
630 | c->value = vv->hflip; | ||
631 | DEB_D(("V4L2_CID_HFLIP: %d\n", c->value)); | ||
632 | break; | ||
633 | default: | ||
634 | return -EINVAL; | ||
860 | } | 635 | } |
861 | if( 0 != (dev->ext_vv_data->ioctls[ee].flags & SAA7146_BEFORE) ) { | 636 | return 0; |
862 | DEB_D(("extension handles ioctl before.\n")); | 637 | } |
863 | result = dev->ext_vv_data->ioctl(fh, cmd, arg); | 638 | |
864 | if( -EAGAIN != result ) { | 639 | static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c) |
865 | return result; | 640 | { |
866 | } | 641 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; |
642 | struct saa7146_vv *vv = dev->vv_data; | ||
643 | const struct v4l2_queryctrl *ctrl; | ||
644 | |||
645 | ctrl = ctrl_by_id(c->id); | ||
646 | if (NULL == ctrl) { | ||
647 | DEB_D(("unknown control %d\n", c->id)); | ||
648 | return -EINVAL; | ||
867 | } | 649 | } |
868 | 650 | ||
869 | /* fixme: add handle "after" case (is it still needed?) */ | 651 | mutex_lock(&dev->lock); |
652 | |||
653 | switch (ctrl->type) { | ||
654 | case V4L2_CTRL_TYPE_BOOLEAN: | ||
655 | case V4L2_CTRL_TYPE_MENU: | ||
656 | case V4L2_CTRL_TYPE_INTEGER: | ||
657 | if (c->value < ctrl->minimum) | ||
658 | c->value = ctrl->minimum; | ||
659 | if (c->value > ctrl->maximum) | ||
660 | c->value = ctrl->maximum; | ||
661 | break; | ||
662 | default: | ||
663 | /* nothing */; | ||
664 | } | ||
870 | 665 | ||
871 | switch (fh->type) { | 666 | switch (c->id) { |
872 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: { | 667 | case V4L2_CID_BRIGHTNESS: { |
873 | ops = &saa7146_video_uops; | 668 | u32 value = saa7146_read(dev, BCS_CTRL); |
874 | q = &fh->video_q; | 669 | value &= 0x00ffffff; |
670 | value |= (c->value << 24); | ||
671 | saa7146_write(dev, BCS_CTRL, value); | ||
672 | saa7146_write(dev, MC2, MASK_22 | MASK_06); | ||
673 | break; | ||
674 | } | ||
675 | case V4L2_CID_CONTRAST: { | ||
676 | u32 value = saa7146_read(dev, BCS_CTRL); | ||
677 | value &= 0xff00ffff; | ||
678 | value |= (c->value << 16); | ||
679 | saa7146_write(dev, BCS_CTRL, value); | ||
680 | saa7146_write(dev, MC2, MASK_22 | MASK_06); | ||
681 | break; | ||
682 | } | ||
683 | case V4L2_CID_SATURATION: { | ||
684 | u32 value = saa7146_read(dev, BCS_CTRL); | ||
685 | value &= 0xffffff00; | ||
686 | value |= (c->value << 0); | ||
687 | saa7146_write(dev, BCS_CTRL, value); | ||
688 | saa7146_write(dev, MC2, MASK_22 | MASK_06); | ||
875 | break; | 689 | break; |
690 | } | ||
691 | case V4L2_CID_HFLIP: | ||
692 | /* fixme: we can support changing VFLIP and HFLIP here... */ | ||
693 | if (IS_CAPTURE_ACTIVE(fh) != 0) { | ||
694 | DEB_D(("V4L2_CID_HFLIP while active capture.\n")); | ||
695 | mutex_unlock(&dev->lock); | ||
696 | return -EINVAL; | ||
876 | } | 697 | } |
877 | case V4L2_BUF_TYPE_VBI_CAPTURE: { | 698 | vv->hflip = c->value; |
878 | ops = &saa7146_vbi_uops; | ||
879 | q = &fh->vbi_q; | ||
880 | break; | 699 | break; |
700 | case V4L2_CID_VFLIP: | ||
701 | if (IS_CAPTURE_ACTIVE(fh) != 0) { | ||
702 | DEB_D(("V4L2_CID_VFLIP while active capture.\n")); | ||
703 | mutex_unlock(&dev->lock); | ||
704 | return -EINVAL; | ||
881 | } | 705 | } |
706 | vv->vflip = c->value; | ||
707 | break; | ||
882 | default: | 708 | default: |
883 | BUG(); | 709 | mutex_unlock(&dev->lock); |
884 | return 0; | 710 | return -EINVAL; |
885 | } | 711 | } |
712 | mutex_unlock(&dev->lock); | ||
886 | 713 | ||
887 | switch (cmd) { | 714 | if (IS_OVERLAY_ACTIVE(fh) != 0) { |
888 | case VIDIOC_QUERYCAP: | 715 | saa7146_stop_preview(fh); |
889 | { | 716 | saa7146_start_preview(fh); |
890 | struct v4l2_capability *cap = arg; | ||
891 | memset(cap,0,sizeof(*cap)); | ||
892 | |||
893 | DEB_EE(("VIDIOC_QUERYCAP\n")); | ||
894 | |||
895 | strcpy((char *)cap->driver, "saa7146 v4l2"); | ||
896 | strlcpy((char *)cap->card, dev->ext->name, sizeof(cap->card)); | ||
897 | sprintf((char *)cap->bus_info,"PCI:%s", pci_name(dev->pci)); | ||
898 | cap->version = SAA7146_VERSION_CODE; | ||
899 | cap->capabilities = | ||
900 | V4L2_CAP_VIDEO_CAPTURE | | ||
901 | V4L2_CAP_VIDEO_OVERLAY | | ||
902 | V4L2_CAP_READWRITE | | ||
903 | V4L2_CAP_STREAMING; | ||
904 | cap->capabilities |= dev->ext_vv_data->capabilities; | ||
905 | return 0; | ||
906 | } | 717 | } |
907 | case VIDIOC_G_FBUF: | 718 | return 0; |
908 | { | 719 | } |
909 | struct v4l2_framebuffer *fb = arg; | ||
910 | 720 | ||
911 | DEB_EE(("VIDIOC_G_FBUF\n")); | 721 | static int vidioc_g_parm(struct file *file, void *fh, |
722 | struct v4l2_streamparm *parm) | ||
723 | { | ||
724 | if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
725 | return -EINVAL; | ||
726 | parm->parm.capture.readbuffers = 1; | ||
727 | /* fixme: only for PAL! */ | ||
728 | parm->parm.capture.timeperframe.numerator = 1; | ||
729 | parm->parm.capture.timeperframe.denominator = 25; | ||
730 | return 0; | ||
731 | } | ||
912 | 732 | ||
913 | *fb = vv->ov_fb; | 733 | static int vidioc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) |
914 | fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; | 734 | { |
915 | return 0; | 735 | f->fmt.pix = ((struct saa7146_fh *)fh)->video_fmt; |
916 | } | 736 | return 0; |
917 | case VIDIOC_S_FBUF: | 737 | } |
918 | { | ||
919 | struct v4l2_framebuffer *fb = arg; | ||
920 | struct saa7146_format *fmt; | ||
921 | 738 | ||
922 | DEB_EE(("VIDIOC_S_FBUF\n")); | 739 | static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f) |
740 | { | ||
741 | f->fmt.win = ((struct saa7146_fh *)fh)->ov.win; | ||
742 | return 0; | ||
743 | } | ||
923 | 744 | ||
924 | if(!capable(CAP_SYS_ADMIN) && | 745 | static int vidioc_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f) |
925 | !capable(CAP_SYS_RAWIO)) | 746 | { |
926 | return -EPERM; | 747 | f->fmt.vbi = ((struct saa7146_fh *)fh)->vbi_fmt; |
748 | return 0; | ||
749 | } | ||
927 | 750 | ||
928 | /* check args */ | 751 | static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) |
929 | fmt = format_by_fourcc(dev,fb->fmt.pixelformat); | 752 | { |
930 | if (NULL == fmt) { | 753 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; |
931 | return -EINVAL; | 754 | struct saa7146_vv *vv = dev->vv_data; |
932 | } | 755 | struct saa7146_format *fmt; |
756 | enum v4l2_field field; | ||
757 | int maxw, maxh; | ||
758 | int calc_bpl; | ||
933 | 759 | ||
934 | /* planar formats are not allowed for overlay video, clipping and video dma would clash */ | 760 | DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh)); |
935 | if (0 != (fmt->flags & FORMAT_IS_PLANAR)) { | ||
936 | DEB_S(("planar pixelformat '%4.4s' not allowed for overlay\n",(char *)&fmt->pixelformat)); | ||
937 | } | ||
938 | 761 | ||
939 | /* check if overlay is running */ | 762 | fmt = format_by_fourcc(dev, f->fmt.pix.pixelformat); |
940 | if (IS_OVERLAY_ACTIVE(fh) != 0) { | 763 | if (NULL == fmt) |
941 | if (vv->video_fh != fh) { | 764 | return -EINVAL; |
942 | DEB_D(("refusing to change framebuffer informations while overlay is active in another open.\n")); | ||
943 | return -EBUSY; | ||
944 | } | ||
945 | } | ||
946 | 765 | ||
947 | mutex_lock(&dev->lock); | 766 | field = f->fmt.pix.field; |
767 | maxw = vv->standard->h_max_out; | ||
768 | maxh = vv->standard->v_max_out; | ||
948 | 769 | ||
949 | /* ok, accept it */ | 770 | if (V4L2_FIELD_ANY == field) { |
950 | vv->ov_fb = *fb; | 771 | field = (f->fmt.pix.height > maxh / 2) |
951 | vv->ov_fmt = fmt; | 772 | ? V4L2_FIELD_INTERLACED |
952 | if (0 == vv->ov_fb.fmt.bytesperline) | 773 | : V4L2_FIELD_BOTTOM; |
953 | vv->ov_fb.fmt.bytesperline = | 774 | } |
954 | vv->ov_fb.fmt.width*fmt->depth/8; | 775 | switch (field) { |
776 | case V4L2_FIELD_ALTERNATE: | ||
777 | vv->last_field = V4L2_FIELD_TOP; | ||
778 | maxh = maxh / 2; | ||
779 | break; | ||
780 | case V4L2_FIELD_TOP: | ||
781 | case V4L2_FIELD_BOTTOM: | ||
782 | vv->last_field = V4L2_FIELD_INTERLACED; | ||
783 | maxh = maxh / 2; | ||
784 | break; | ||
785 | case V4L2_FIELD_INTERLACED: | ||
786 | vv->last_field = V4L2_FIELD_INTERLACED; | ||
787 | break; | ||
788 | default: | ||
789 | DEB_D(("no known field mode '%d'.\n", field)); | ||
790 | return -EINVAL; | ||
791 | } | ||
955 | 792 | ||
956 | mutex_unlock(&dev->lock); | 793 | f->fmt.pix.field = field; |
794 | if (f->fmt.pix.width > maxw) | ||
795 | f->fmt.pix.width = maxw; | ||
796 | if (f->fmt.pix.height > maxh) | ||
797 | f->fmt.pix.height = maxh; | ||
957 | 798 | ||
958 | return 0; | 799 | calc_bpl = (f->fmt.pix.width * fmt->depth) / 8; |
959 | } | ||
960 | case VIDIOC_ENUM_FMT: | ||
961 | { | ||
962 | struct v4l2_fmtdesc *f = arg; | ||
963 | |||
964 | switch (f->type) { | ||
965 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
966 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | ||
967 | if (f->index >= NUM_FORMATS) | ||
968 | return -EINVAL; | ||
969 | strlcpy((char *)f->description, formats[f->index].name, | ||
970 | sizeof(f->description)); | ||
971 | f->pixelformat = formats[f->index].pixelformat; | ||
972 | f->flags = 0; | ||
973 | memset(f->reserved, 0, sizeof(f->reserved)); | ||
974 | break; | ||
975 | default: | ||
976 | return -EINVAL; | ||
977 | } | ||
978 | 800 | ||
979 | DEB_EE(("VIDIOC_ENUM_FMT: type:%d, index:%d\n",f->type,f->index)); | 801 | if (f->fmt.pix.bytesperline < calc_bpl) |
980 | return 0; | 802 | f->fmt.pix.bytesperline = calc_bpl; |
981 | } | ||
982 | case VIDIOC_QUERYCTRL: | ||
983 | { | ||
984 | const struct v4l2_queryctrl *ctrl; | ||
985 | struct v4l2_queryctrl *c = arg; | ||
986 | 803 | ||
987 | if ((c->id < V4L2_CID_BASE || | 804 | if (f->fmt.pix.bytesperline > (2 * PAGE_SIZE * fmt->depth) / 8) /* arbitrary constraint */ |
988 | c->id >= V4L2_CID_LASTP1) && | 805 | f->fmt.pix.bytesperline = calc_bpl; |
989 | (c->id < V4L2_CID_PRIVATE_BASE || | ||
990 | c->id >= V4L2_CID_PRIVATE_LASTP1)) | ||
991 | return -EINVAL; | ||
992 | 806 | ||
993 | ctrl = ctrl_by_id(c->id); | 807 | f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; |
994 | if( NULL == ctrl ) { | 808 | DEB_D(("w:%d, h:%d, bytesperline:%d, sizeimage:%d\n", f->fmt.pix.width, |
995 | return -EINVAL; | 809 | f->fmt.pix.height, f->fmt.pix.bytesperline, f->fmt.pix.sizeimage)); |
996 | /* | ||
997 | c->flags = V4L2_CTRL_FLAG_DISABLED; | ||
998 | return 0; | ||
999 | */ | ||
1000 | } | ||
1001 | 810 | ||
1002 | DEB_EE(("VIDIOC_QUERYCTRL: id:%d\n",c->id)); | 811 | return 0; |
1003 | *c = *ctrl; | 812 | } |
1004 | return 0; | 813 | |
814 | |||
815 | static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f) | ||
816 | { | ||
817 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
818 | struct saa7146_vv *vv = dev->vv_data; | ||
819 | struct v4l2_window *win = &f->fmt.win; | ||
820 | enum v4l2_field field; | ||
821 | int maxw, maxh; | ||
822 | |||
823 | DEB_EE(("dev:%p\n", dev)); | ||
824 | |||
825 | if (NULL == vv->ov_fb.base) { | ||
826 | DEB_D(("no fb base set.\n")); | ||
827 | return -EINVAL; | ||
1005 | } | 828 | } |
1006 | case VIDIOC_G_CTRL: { | 829 | if (NULL == vv->ov_fmt) { |
1007 | DEB_EE(("VIDIOC_G_CTRL\n")); | 830 | DEB_D(("no fb fmt set.\n")); |
1008 | return get_control(fh,arg); | 831 | return -EINVAL; |
1009 | } | 832 | } |
1010 | case VIDIOC_S_CTRL: | 833 | if (win->w.width < 48 || win->w.height < 32) { |
1011 | { | 834 | DEB_D(("min width/height. (%d,%d)\n", win->w.width, win->w.height)); |
1012 | DEB_EE(("VIDIOC_S_CTRL\n")); | 835 | return -EINVAL; |
1013 | err = set_control(fh,arg); | ||
1014 | return err; | ||
1015 | } | 836 | } |
1016 | case VIDIOC_G_PARM: | 837 | if (win->clipcount > 16) { |
1017 | { | 838 | DEB_D(("clipcount too big.\n")); |
1018 | struct v4l2_streamparm *parm = arg; | 839 | return -EINVAL; |
1019 | if( parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ) { | ||
1020 | return -EINVAL; | ||
1021 | } | ||
1022 | memset(&parm->parm.capture,0,sizeof(struct v4l2_captureparm)); | ||
1023 | parm->parm.capture.readbuffers = 1; | ||
1024 | // fixme: only for PAL! | ||
1025 | parm->parm.capture.timeperframe.numerator = 1; | ||
1026 | parm->parm.capture.timeperframe.denominator = 25; | ||
1027 | return 0; | ||
1028 | } | 840 | } |
1029 | case VIDIOC_G_FMT: | 841 | |
1030 | { | 842 | field = win->field; |
1031 | struct v4l2_format *f = arg; | 843 | maxw = vv->standard->h_max_out; |
1032 | DEB_EE(("VIDIOC_G_FMT\n")); | 844 | maxh = vv->standard->v_max_out; |
1033 | return g_fmt(fh,f); | 845 | |
846 | if (V4L2_FIELD_ANY == field) { | ||
847 | field = (win->w.height > maxh / 2) | ||
848 | ? V4L2_FIELD_INTERLACED | ||
849 | : V4L2_FIELD_TOP; | ||
850 | } | ||
851 | switch (field) { | ||
852 | case V4L2_FIELD_TOP: | ||
853 | case V4L2_FIELD_BOTTOM: | ||
854 | case V4L2_FIELD_ALTERNATE: | ||
855 | maxh = maxh / 2; | ||
856 | break; | ||
857 | case V4L2_FIELD_INTERLACED: | ||
858 | break; | ||
859 | default: | ||
860 | DEB_D(("no known field mode '%d'.\n", field)); | ||
861 | return -EINVAL; | ||
1034 | } | 862 | } |
1035 | case VIDIOC_S_FMT: | 863 | |
1036 | { | 864 | win->field = field; |
1037 | struct v4l2_format *f = arg; | 865 | if (win->w.width > maxw) |
1038 | DEB_EE(("VIDIOC_S_FMT\n")); | 866 | win->w.width = maxw; |
1039 | return s_fmt(fh,f); | 867 | if (win->w.height > maxh) |
868 | win->w.height = maxh; | ||
869 | |||
870 | return 0; | ||
871 | } | ||
872 | |||
873 | static int vidioc_s_fmt_vid_cap(struct file *file, void *__fh, struct v4l2_format *f) | ||
874 | { | ||
875 | struct saa7146_fh *fh = __fh; | ||
876 | struct saa7146_dev *dev = fh->dev; | ||
877 | struct saa7146_vv *vv = dev->vv_data; | ||
878 | int err; | ||
879 | |||
880 | DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh)); | ||
881 | if (IS_CAPTURE_ACTIVE(fh) != 0) { | ||
882 | DEB_EE(("streaming capture is active\n")); | ||
883 | return -EBUSY; | ||
1040 | } | 884 | } |
1041 | case VIDIOC_TRY_FMT: | 885 | err = vidioc_try_fmt_vid_cap(file, fh, f); |
1042 | { | 886 | if (0 != err) |
1043 | struct v4l2_format *f = arg; | 887 | return err; |
1044 | DEB_EE(("VIDIOC_TRY_FMT\n")); | 888 | fh->video_fmt = f->fmt.pix; |
1045 | return try_fmt(fh,f); | 889 | DEB_EE(("set to pixelformat '%4.4s'\n", (char *)&fh->video_fmt.pixelformat)); |
890 | return 0; | ||
891 | } | ||
892 | |||
893 | static int vidioc_s_fmt_vid_overlay(struct file *file, void *__fh, struct v4l2_format *f) | ||
894 | { | ||
895 | struct saa7146_fh *fh = __fh; | ||
896 | struct saa7146_dev *dev = fh->dev; | ||
897 | struct saa7146_vv *vv = dev->vv_data; | ||
898 | int err; | ||
899 | |||
900 | DEB_EE(("V4L2_BUF_TYPE_VIDEO_OVERLAY: dev:%p, fh:%p\n", dev, fh)); | ||
901 | err = vidioc_try_fmt_vid_overlay(file, fh, f); | ||
902 | if (0 != err) | ||
903 | return err; | ||
904 | mutex_lock(&dev->lock); | ||
905 | fh->ov.win = f->fmt.win; | ||
906 | fh->ov.nclips = f->fmt.win.clipcount; | ||
907 | if (fh->ov.nclips > 16) | ||
908 | fh->ov.nclips = 16; | ||
909 | if (copy_from_user(fh->ov.clips, f->fmt.win.clips, | ||
910 | sizeof(struct v4l2_clip) * fh->ov.nclips)) { | ||
911 | mutex_unlock(&dev->lock); | ||
912 | return -EFAULT; | ||
1046 | } | 913 | } |
1047 | case VIDIOC_G_STD: | 914 | |
1048 | { | 915 | /* fh->ov.fh is used to indicate that we have valid overlay informations, too */ |
1049 | v4l2_std_id *id = arg; | 916 | fh->ov.fh = fh; |
1050 | DEB_EE(("VIDIOC_G_STD\n")); | 917 | |
1051 | *id = vv->standard->id; | 918 | mutex_unlock(&dev->lock); |
1052 | return 0; | 919 | |
920 | /* check if our current overlay is active */ | ||
921 | if (IS_OVERLAY_ACTIVE(fh) != 0) { | ||
922 | saa7146_stop_preview(fh); | ||
923 | saa7146_start_preview(fh); | ||
1053 | } | 924 | } |
925 | return 0; | ||
926 | } | ||
927 | |||
928 | static int vidioc_g_std(struct file *file, void *fh, v4l2_std_id *norm) | ||
929 | { | ||
930 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
931 | struct saa7146_vv *vv = dev->vv_data; | ||
932 | |||
933 | *norm = vv->standard->id; | ||
934 | return 0; | ||
935 | } | ||
936 | |||
1054 | /* the saa7146 supfhrts (used in conjunction with the saa7111a for example) | 937 | /* the saa7146 supfhrts (used in conjunction with the saa7111a for example) |
1055 | PAL / NTSC / SECAM. if your hardware does not (or does more) | 938 | PAL / NTSC / SECAM. if your hardware does not (or does more) |
1056 | -- override this function in your extension */ | 939 | -- override this function in your extension */ |
940 | /* | ||
1057 | case VIDIOC_ENUMSTD: | 941 | case VIDIOC_ENUMSTD: |
1058 | { | 942 | { |
1059 | struct v4l2_standard *e = arg; | 943 | struct v4l2_standard *e = arg; |
@@ -1066,162 +950,228 @@ long saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
1066 | } | 950 | } |
1067 | return -EINVAL; | 951 | return -EINVAL; |
1068 | } | 952 | } |
1069 | case VIDIOC_S_STD: | 953 | */ |
1070 | { | ||
1071 | v4l2_std_id *id = arg; | ||
1072 | int found = 0; | ||
1073 | int i; | ||
1074 | |||
1075 | DEB_EE(("VIDIOC_S_STD\n")); | ||
1076 | 954 | ||
1077 | if ((vv->video_status & STATUS_CAPTURE) == STATUS_CAPTURE) { | 955 | static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id) |
1078 | DEB_D(("cannot change video standard while streaming capture is active\n")); | 956 | { |
1079 | return -EBUSY; | 957 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; |
1080 | } | 958 | struct saa7146_vv *vv = dev->vv_data; |
959 | int found = 0; | ||
960 | int err, i; | ||
1081 | 961 | ||
1082 | if ((vv->video_status & STATUS_OVERLAY) != 0) { | 962 | DEB_EE(("VIDIOC_S_STD\n")); |
1083 | vv->ov_suspend = vv->video_fh; | ||
1084 | err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */ | ||
1085 | if (0 != err) { | ||
1086 | DEB_D(("suspending video failed. aborting\n")); | ||
1087 | return err; | ||
1088 | } | ||
1089 | } | ||
1090 | 963 | ||
1091 | mutex_lock(&dev->lock); | 964 | if ((vv->video_status & STATUS_CAPTURE) == STATUS_CAPTURE) { |
965 | DEB_D(("cannot change video standard while streaming capture is active\n")); | ||
966 | return -EBUSY; | ||
967 | } | ||
1092 | 968 | ||
1093 | for(i = 0; i < dev->ext_vv_data->num_stds; i++) | 969 | if ((vv->video_status & STATUS_OVERLAY) != 0) { |
1094 | if (*id & dev->ext_vv_data->stds[i].id) | 970 | vv->ov_suspend = vv->video_fh; |
1095 | break; | 971 | err = saa7146_stop_preview(vv->video_fh); /* side effect: video_status is now 0, video_fh is NULL */ |
1096 | if (i != dev->ext_vv_data->num_stds) { | 972 | if (0 != err) { |
1097 | vv->standard = &dev->ext_vv_data->stds[i]; | 973 | DEB_D(("suspending video failed. aborting\n")); |
1098 | if( NULL != dev->ext_vv_data->std_callback ) | 974 | return err; |
1099 | dev->ext_vv_data->std_callback(dev, vv->standard); | ||
1100 | found = 1; | ||
1101 | } | 975 | } |
976 | } | ||
1102 | 977 | ||
1103 | mutex_unlock(&dev->lock); | 978 | mutex_lock(&dev->lock); |
1104 | 979 | ||
1105 | if (vv->ov_suspend != NULL) { | 980 | for (i = 0; i < dev->ext_vv_data->num_stds; i++) |
1106 | saa7146_start_preview(vv->ov_suspend); | 981 | if (*id & dev->ext_vv_data->stds[i].id) |
1107 | vv->ov_suspend = NULL; | 982 | break; |
1108 | } | 983 | if (i != dev->ext_vv_data->num_stds) { |
984 | vv->standard = &dev->ext_vv_data->stds[i]; | ||
985 | if (NULL != dev->ext_vv_data->std_callback) | ||
986 | dev->ext_vv_data->std_callback(dev, vv->standard); | ||
987 | found = 1; | ||
988 | } | ||
1109 | 989 | ||
1110 | if( 0 == found ) { | 990 | mutex_unlock(&dev->lock); |
1111 | DEB_EE(("VIDIOC_S_STD: standard not found.\n")); | ||
1112 | return -EINVAL; | ||
1113 | } | ||
1114 | 991 | ||
1115 | DEB_EE(("VIDIOC_S_STD: set to standard to '%s'\n",vv->standard->name)); | 992 | if (vv->ov_suspend != NULL) { |
1116 | return 0; | 993 | saa7146_start_preview(vv->ov_suspend); |
994 | vv->ov_suspend = NULL; | ||
1117 | } | 995 | } |
1118 | case VIDIOC_OVERLAY: | ||
1119 | { | ||
1120 | int on = *(int *)arg; | ||
1121 | 996 | ||
1122 | DEB_D(("VIDIOC_OVERLAY on:%d\n",on)); | 997 | if (!found) { |
1123 | if (on != 0) { | 998 | DEB_EE(("VIDIOC_S_STD: standard not found.\n")); |
1124 | err = saa7146_start_preview(fh); | 999 | return -EINVAL; |
1125 | } else { | ||
1126 | err = saa7146_stop_preview(fh); | ||
1127 | } | ||
1128 | return err; | ||
1129 | } | ||
1130 | case VIDIOC_REQBUFS: { | ||
1131 | struct v4l2_requestbuffers *req = arg; | ||
1132 | DEB_D(("VIDIOC_REQBUFS, type:%d\n",req->type)); | ||
1133 | return videobuf_reqbufs(q,req); | ||
1134 | } | ||
1135 | case VIDIOC_QUERYBUF: { | ||
1136 | struct v4l2_buffer *buf = arg; | ||
1137 | DEB_D(("VIDIOC_QUERYBUF, type:%d, offset:%d\n",buf->type,buf->m.offset)); | ||
1138 | return videobuf_querybuf(q,buf); | ||
1139 | } | ||
1140 | case VIDIOC_QBUF: { | ||
1141 | struct v4l2_buffer *buf = arg; | ||
1142 | int ret = 0; | ||
1143 | ret = videobuf_qbuf(q,buf); | ||
1144 | DEB_D(("VIDIOC_QBUF: ret:%d, index:%d\n",ret,buf->index)); | ||
1145 | return ret; | ||
1146 | } | ||
1147 | case VIDIOC_DQBUF: { | ||
1148 | struct v4l2_buffer *buf = arg; | ||
1149 | int ret = 0; | ||
1150 | ret = videobuf_dqbuf(q,buf,file->f_flags & O_NONBLOCK); | ||
1151 | DEB_D(("VIDIOC_DQBUF: ret:%d, index:%d\n",ret,buf->index)); | ||
1152 | return ret; | ||
1153 | } | 1000 | } |
1154 | case VIDIOC_STREAMON: { | ||
1155 | int *type = arg; | ||
1156 | DEB_D(("VIDIOC_STREAMON, type:%d\n",*type)); | ||
1157 | 1001 | ||
1158 | err = video_begin(fh); | 1002 | DEB_EE(("VIDIOC_S_STD: set to standard to '%s'\n", vv->standard->name)); |
1159 | if( 0 != err) { | 1003 | return 0; |
1160 | return err; | 1004 | } |
1161 | } | ||
1162 | err = videobuf_streamon(q); | ||
1163 | return err; | ||
1164 | } | ||
1165 | case VIDIOC_STREAMOFF: { | ||
1166 | int *type = arg; | ||
1167 | 1005 | ||
1168 | DEB_D(("VIDIOC_STREAMOFF, type:%d\n",*type)); | 1006 | static int vidioc_overlay(struct file *file, void *fh, unsigned int on) |
1007 | { | ||
1008 | int err; | ||
1169 | 1009 | ||
1170 | /* ugly: we need to copy some checks from video_end(), | 1010 | DEB_D(("VIDIOC_OVERLAY on:%d\n", on)); |
1171 | because videobuf_streamoff() relies on the capture running. | 1011 | if (on) |
1172 | check and fix this */ | 1012 | err = saa7146_start_preview(fh); |
1173 | if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) { | 1013 | else |
1174 | DEB_S(("not capturing.\n")); | 1014 | err = saa7146_stop_preview(fh); |
1175 | return 0; | 1015 | return err; |
1176 | } | 1016 | } |
1177 | 1017 | ||
1178 | if (vv->video_fh != fh) { | 1018 | static int vidioc_reqbufs(struct file *file, void *__fh, struct v4l2_requestbuffers *b) |
1179 | DEB_S(("capturing, but in another open.\n")); | 1019 | { |
1180 | return -EBUSY; | 1020 | struct saa7146_fh *fh = __fh; |
1181 | } | ||
1182 | 1021 | ||
1183 | err = videobuf_streamoff(q); | 1022 | if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1184 | if (0 != err) { | 1023 | return videobuf_reqbufs(&fh->video_q, b); |
1185 | DEB_D(("warning: videobuf_streamoff() failed.\n")); | 1024 | if (b->type == V4L2_BUF_TYPE_VBI_CAPTURE) |
1186 | video_end(fh, file); | 1025 | return videobuf_reqbufs(&fh->vbi_q, b); |
1187 | } else { | 1026 | return -EINVAL; |
1188 | err = video_end(fh, file); | 1027 | } |
1189 | } | 1028 | |
1190 | return err; | 1029 | static int vidioc_querybuf(struct file *file, void *__fh, struct v4l2_buffer *buf) |
1191 | } | 1030 | { |
1192 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | 1031 | struct saa7146_fh *fh = __fh; |
1193 | case VIDIOCGMBUF: | ||
1194 | { | ||
1195 | struct video_mbuf *mbuf = arg; | ||
1196 | int i; | ||
1197 | 1032 | ||
1198 | /* fixme: number of capture buffers and sizes for v4l apps */ | 1033 | if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1199 | int gbuffers = 2; | 1034 | return videobuf_querybuf(&fh->video_q, buf); |
1200 | int gbufsize = 768*576*4; | 1035 | if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE) |
1036 | return videobuf_querybuf(&fh->vbi_q, buf); | ||
1037 | return -EINVAL; | ||
1038 | } | ||
1201 | 1039 | ||
1202 | DEB_D(("VIDIOCGMBUF \n")); | 1040 | static int vidioc_qbuf(struct file *file, void *__fh, struct v4l2_buffer *buf) |
1041 | { | ||
1042 | struct saa7146_fh *fh = __fh; | ||
1203 | 1043 | ||
1204 | q = &fh->video_q; | 1044 | if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) |
1205 | err = videobuf_mmap_setup(q,gbuffers,gbufsize, | 1045 | return videobuf_qbuf(&fh->video_q, buf); |
1206 | V4L2_MEMORY_MMAP); | 1046 | if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE) |
1207 | if (err < 0) | 1047 | return videobuf_qbuf(&fh->vbi_q, buf); |
1208 | return err; | 1048 | return -EINVAL; |
1049 | } | ||
1050 | |||
1051 | static int vidioc_dqbuf(struct file *file, void *__fh, struct v4l2_buffer *buf) | ||
1052 | { | ||
1053 | struct saa7146_fh *fh = __fh; | ||
1054 | |||
1055 | if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
1056 | return videobuf_dqbuf(&fh->video_q, buf, file->f_flags & O_NONBLOCK); | ||
1057 | if (buf->type == V4L2_BUF_TYPE_VBI_CAPTURE) | ||
1058 | return videobuf_dqbuf(&fh->vbi_q, buf, file->f_flags & O_NONBLOCK); | ||
1059 | return -EINVAL; | ||
1060 | } | ||
1061 | |||
1062 | static int vidioc_streamon(struct file *file, void *__fh, enum v4l2_buf_type type) | ||
1063 | { | ||
1064 | struct saa7146_fh *fh = __fh; | ||
1065 | int err; | ||
1066 | |||
1067 | DEB_D(("VIDIOC_STREAMON, type:%d\n", type)); | ||
1068 | |||
1069 | err = video_begin(fh); | ||
1070 | if (err) | ||
1071 | return err; | ||
1072 | if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
1073 | return videobuf_streamon(&fh->video_q); | ||
1074 | if (type == V4L2_BUF_TYPE_VBI_CAPTURE) | ||
1075 | return videobuf_streamon(&fh->vbi_q); | ||
1076 | return -EINVAL; | ||
1077 | } | ||
1078 | |||
1079 | static int vidioc_streamoff(struct file *file, void *__fh, enum v4l2_buf_type type) | ||
1080 | { | ||
1081 | struct saa7146_fh *fh = __fh; | ||
1082 | struct saa7146_dev *dev = fh->dev; | ||
1083 | struct saa7146_vv *vv = dev->vv_data; | ||
1084 | int err; | ||
1085 | |||
1086 | DEB_D(("VIDIOC_STREAMOFF, type:%d\n", type)); | ||
1209 | 1087 | ||
1210 | gbuffers = err; | 1088 | /* ugly: we need to copy some checks from video_end(), |
1211 | memset(mbuf,0,sizeof(*mbuf)); | 1089 | because videobuf_streamoff() relies on the capture running. |
1212 | mbuf->frames = gbuffers; | 1090 | check and fix this */ |
1213 | mbuf->size = gbuffers * gbufsize; | 1091 | if ((vv->video_status & STATUS_CAPTURE) != STATUS_CAPTURE) { |
1214 | for (i = 0; i < gbuffers; i++) | 1092 | DEB_S(("not capturing.\n")); |
1215 | mbuf->offsets[i] = i * gbufsize; | ||
1216 | return 0; | 1093 | return 0; |
1217 | } | 1094 | } |
1218 | #endif | 1095 | |
1219 | default: | 1096 | if (vv->video_fh != fh) { |
1220 | return v4l_compat_translate_ioctl(file, cmd, arg, | 1097 | DEB_S(("capturing, but in another open.\n")); |
1221 | saa7146_video_do_ioctl); | 1098 | return -EBUSY; |
1222 | } | 1099 | } |
1100 | |||
1101 | err = -EINVAL; | ||
1102 | if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
1103 | err = videobuf_streamoff(&fh->video_q); | ||
1104 | else if (type == V4L2_BUF_TYPE_VBI_CAPTURE) | ||
1105 | err = videobuf_streamoff(&fh->vbi_q); | ||
1106 | if (0 != err) { | ||
1107 | DEB_D(("warning: videobuf_streamoff() failed.\n")); | ||
1108 | video_end(fh, file); | ||
1109 | } else { | ||
1110 | err = video_end(fh, file); | ||
1111 | } | ||
1112 | return err; | ||
1113 | } | ||
1114 | |||
1115 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | ||
1116 | static int vidiocgmbuf(struct file *file, void *__fh, struct video_mbuf *mbuf) | ||
1117 | { | ||
1118 | struct saa7146_fh *fh = __fh; | ||
1119 | struct videobuf_queue *q = &fh->video_q; | ||
1120 | int err, i; | ||
1121 | |||
1122 | /* fixme: number of capture buffers and sizes for v4l apps */ | ||
1123 | int gbuffers = 2; | ||
1124 | int gbufsize = 768 * 576 * 4; | ||
1125 | |||
1126 | DEB_D(("VIDIOCGMBUF \n")); | ||
1127 | |||
1128 | q = &fh->video_q; | ||
1129 | err = videobuf_mmap_setup(q, gbuffers, gbufsize, | ||
1130 | V4L2_MEMORY_MMAP); | ||
1131 | if (err < 0) | ||
1132 | return err; | ||
1133 | |||
1134 | gbuffers = err; | ||
1135 | memset(mbuf, 0, sizeof(*mbuf)); | ||
1136 | mbuf->frames = gbuffers; | ||
1137 | mbuf->size = gbuffers * gbufsize; | ||
1138 | for (i = 0; i < gbuffers; i++) | ||
1139 | mbuf->offsets[i] = i * gbufsize; | ||
1223 | return 0; | 1140 | return 0; |
1224 | } | 1141 | } |
1142 | #endif | ||
1143 | |||
1144 | const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = { | ||
1145 | .vidioc_querycap = vidioc_querycap, | ||
1146 | .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, | ||
1147 | .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_overlay, | ||
1148 | .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, | ||
1149 | .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, | ||
1150 | .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, | ||
1151 | .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_vid_overlay, | ||
1152 | .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay, | ||
1153 | .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay, | ||
1154 | .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, | ||
1155 | |||
1156 | .vidioc_overlay = vidioc_overlay, | ||
1157 | .vidioc_g_fbuf = vidioc_g_fbuf, | ||
1158 | .vidioc_s_fbuf = vidioc_s_fbuf, | ||
1159 | .vidioc_reqbufs = vidioc_reqbufs, | ||
1160 | .vidioc_querybuf = vidioc_querybuf, | ||
1161 | .vidioc_qbuf = vidioc_qbuf, | ||
1162 | .vidioc_dqbuf = vidioc_dqbuf, | ||
1163 | .vidioc_g_std = vidioc_g_std, | ||
1164 | .vidioc_s_std = vidioc_s_std, | ||
1165 | .vidioc_queryctrl = vidioc_queryctrl, | ||
1166 | .vidioc_g_ctrl = vidioc_g_ctrl, | ||
1167 | .vidioc_s_ctrl = vidioc_s_ctrl, | ||
1168 | .vidioc_streamon = vidioc_streamon, | ||
1169 | .vidioc_streamoff = vidioc_streamoff, | ||
1170 | .vidioc_g_parm = vidioc_g_parm, | ||
1171 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | ||
1172 | .vidiocgmbuf = vidiocgmbuf, | ||
1173 | #endif | ||
1174 | }; | ||
1225 | 1175 | ||
1226 | /*********************************************************************************/ | 1176 | /*********************************************************************************/ |
1227 | /* buffer handling functions */ | 1177 | /* buffer handling functions */ |
diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c index c5b9c70563dc..04334058f8f8 100644 --- a/drivers/media/dvb/ttpci/av7110_v4l.c +++ b/drivers/media/dvb/ttpci/av7110_v4l.c | |||
@@ -316,253 +316,260 @@ static int av7110_dvb_c_switch(struct saa7146_fh *fh) | |||
316 | return 0; | 316 | return 0; |
317 | } | 317 | } |
318 | 318 | ||
319 | static long av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) | 319 | static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t) |
320 | { | 320 | { |
321 | struct saa7146_dev *dev = fh->dev; | 321 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; |
322 | struct av7110 *av7110 = (struct av7110*) dev->ext_priv; | 322 | struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; |
323 | dprintk(4, "saa7146_dev: %p\n", dev); | 323 | u16 stereo_det; |
324 | s8 stereo; | ||
324 | 325 | ||
325 | switch (cmd) { | 326 | dprintk(2, "VIDIOC_G_TUNER: %d\n", t->index); |
326 | case VIDIOC_G_TUNER: | ||
327 | { | ||
328 | struct v4l2_tuner *t = arg; | ||
329 | u16 stereo_det; | ||
330 | s8 stereo; | ||
331 | 327 | ||
332 | dprintk(2, "VIDIOC_G_TUNER: %d\n", t->index); | 328 | if (!av7110->analog_tuner_flags || t->index != 0) |
329 | return -EINVAL; | ||
333 | 330 | ||
334 | if (!av7110->analog_tuner_flags || t->index != 0) | 331 | memset(t, 0, sizeof(*t)); |
335 | return -EINVAL; | 332 | strcpy((char *)t->name, "Television"); |
333 | |||
334 | t->type = V4L2_TUNER_ANALOG_TV; | ||
335 | t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | | ||
336 | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; | ||
337 | t->rangelow = 772; /* 48.25 MHZ / 62.5 kHz = 772, see fi1216mk2-specs, page 2 */ | ||
338 | t->rangehigh = 13684; /* 855.25 MHz / 62.5 kHz = 13684 */ | ||
339 | /* FIXME: add the real signal strength here */ | ||
340 | t->signal = 0xffff; | ||
341 | t->afc = 0; | ||
342 | |||
343 | /* FIXME: standard / stereo detection is still broken */ | ||
344 | msp_readreg(av7110, MSP_RD_DEM, 0x007e, &stereo_det); | ||
345 | dprintk(1, "VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det); | ||
346 | msp_readreg(av7110, MSP_RD_DSP, 0x0018, &stereo_det); | ||
347 | dprintk(1, "VIDIOC_G_TUNER: msp3400 stereo detection: 0x%04x\n", stereo_det); | ||
348 | stereo = (s8)(stereo_det >> 8); | ||
349 | if (stereo > 0x10) { | ||
350 | /* stereo */ | ||
351 | t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO; | ||
352 | t->audmode = V4L2_TUNER_MODE_STEREO; | ||
353 | } else if (stereo < -0x10) { | ||
354 | /* bilingual */ | ||
355 | t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; | ||
356 | t->audmode = V4L2_TUNER_MODE_LANG1; | ||
357 | } else /* mono */ | ||
358 | t->rxsubchans = V4L2_TUNER_SUB_MONO; | ||
336 | 359 | ||
337 | memset(t, 0, sizeof(*t)); | 360 | return 0; |
338 | strcpy((char *)t->name, "Television"); | 361 | } |
339 | |||
340 | t->type = V4L2_TUNER_ANALOG_TV; | ||
341 | t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | | ||
342 | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; | ||
343 | t->rangelow = 772; /* 48.25 MHZ / 62.5 kHz = 772, see fi1216mk2-specs, page 2 */ | ||
344 | t->rangehigh = 13684; /* 855.25 MHz / 62.5 kHz = 13684 */ | ||
345 | /* FIXME: add the real signal strength here */ | ||
346 | t->signal = 0xffff; | ||
347 | t->afc = 0; | ||
348 | |||
349 | // FIXME: standard / stereo detection is still broken | ||
350 | msp_readreg(av7110, MSP_RD_DEM, 0x007e, &stereo_det); | ||
351 | dprintk(1, "VIDIOC_G_TUNER: msp3400 TV standard detection: 0x%04x\n", stereo_det); | ||
352 | msp_readreg(av7110, MSP_RD_DSP, 0x0018, &stereo_det); | ||
353 | dprintk(1, "VIDIOC_G_TUNER: msp3400 stereo detection: 0x%04x\n", stereo_det); | ||
354 | stereo = (s8)(stereo_det >> 8); | ||
355 | if (stereo > 0x10) { | ||
356 | /* stereo */ | ||
357 | t->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO; | ||
358 | t->audmode = V4L2_TUNER_MODE_STEREO; | ||
359 | } | ||
360 | else if (stereo < -0x10) { | ||
361 | /* bilingual */ | ||
362 | t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; | ||
363 | t->audmode = V4L2_TUNER_MODE_LANG1; | ||
364 | } | ||
365 | else /* mono */ | ||
366 | t->rxsubchans = V4L2_TUNER_SUB_MONO; | ||
367 | 362 | ||
368 | return 0; | 363 | static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t) |
369 | } | 364 | { |
370 | case VIDIOC_S_TUNER: | 365 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; |
371 | { | 366 | struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; |
372 | struct v4l2_tuner *t = arg; | 367 | u16 fm_matrix, src; |
373 | u16 fm_matrix, src; | 368 | dprintk(2, "VIDIOC_S_TUNER: %d\n", t->index); |
374 | dprintk(2, "VIDIOC_S_TUNER: %d\n", t->index); | ||
375 | 369 | ||
376 | if (!av7110->analog_tuner_flags || av7110->current_input != 1) | 370 | if (!av7110->analog_tuner_flags || av7110->current_input != 1) |
377 | return -EINVAL; | 371 | return -EINVAL; |
378 | 372 | ||
379 | switch (t->audmode) { | 373 | switch (t->audmode) { |
380 | case V4L2_TUNER_MODE_STEREO: | 374 | case V4L2_TUNER_MODE_STEREO: |
381 | dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n"); | 375 | dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_STEREO\n"); |
382 | fm_matrix = 0x3001; // stereo | 376 | fm_matrix = 0x3001; /* stereo */ |
383 | src = 0x0020; | 377 | src = 0x0020; |
384 | break; | 378 | break; |
385 | case V4L2_TUNER_MODE_LANG1_LANG2: | 379 | case V4L2_TUNER_MODE_LANG1_LANG2: |
386 | dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1_LANG2\n"); | 380 | dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1_LANG2\n"); |
387 | fm_matrix = 0x3000; // bilingual | 381 | fm_matrix = 0x3000; /* bilingual */ |
388 | src = 0x0020; | 382 | src = 0x0020; |
389 | break; | 383 | break; |
390 | case V4L2_TUNER_MODE_LANG1: | 384 | case V4L2_TUNER_MODE_LANG1: |
391 | dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n"); | 385 | dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG1\n"); |
392 | fm_matrix = 0x3000; // mono | 386 | fm_matrix = 0x3000; /* mono */ |
393 | src = 0x0000; | 387 | src = 0x0000; |
394 | break; | 388 | break; |
395 | case V4L2_TUNER_MODE_LANG2: | 389 | case V4L2_TUNER_MODE_LANG2: |
396 | dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n"); | 390 | dprintk(2, "VIDIOC_S_TUNER: V4L2_TUNER_MODE_LANG2\n"); |
397 | fm_matrix = 0x3000; // mono | 391 | fm_matrix = 0x3000; /* mono */ |
398 | src = 0x0010; | 392 | src = 0x0010; |
399 | break; | 393 | break; |
400 | default: /* case V4L2_TUNER_MODE_MONO: */ | 394 | default: /* case V4L2_TUNER_MODE_MONO: */ |
401 | dprintk(2, "VIDIOC_S_TUNER: TDA9840_SET_MONO\n"); | 395 | dprintk(2, "VIDIOC_S_TUNER: TDA9840_SET_MONO\n"); |
402 | fm_matrix = 0x3000; // mono | 396 | fm_matrix = 0x3000; /* mono */ |
403 | src = 0x0030; | 397 | src = 0x0030; |
404 | break; | 398 | break; |
405 | } | ||
406 | msp_writereg(av7110, MSP_WR_DSP, 0x000e, fm_matrix); | ||
407 | msp_writereg(av7110, MSP_WR_DSP, 0x0008, src); | ||
408 | msp_writereg(av7110, MSP_WR_DSP, 0x0009, src); | ||
409 | msp_writereg(av7110, MSP_WR_DSP, 0x000a, src); | ||
410 | return 0; | ||
411 | } | 399 | } |
412 | case VIDIOC_G_FREQUENCY: | 400 | msp_writereg(av7110, MSP_WR_DSP, 0x000e, fm_matrix); |
413 | { | 401 | msp_writereg(av7110, MSP_WR_DSP, 0x0008, src); |
414 | struct v4l2_frequency *f = arg; | 402 | msp_writereg(av7110, MSP_WR_DSP, 0x0009, src); |
403 | msp_writereg(av7110, MSP_WR_DSP, 0x000a, src); | ||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *f) | ||
408 | { | ||
409 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
410 | struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; | ||
415 | 411 | ||
416 | dprintk(2, "VIDIOC_G_FREQ: freq:0x%08x.\n", f->frequency); | 412 | dprintk(2, "VIDIOC_G_FREQ: freq:0x%08x.\n", f->frequency); |
417 | 413 | ||
418 | if (!av7110->analog_tuner_flags || av7110->current_input != 1) | 414 | if (!av7110->analog_tuner_flags || av7110->current_input != 1) |
419 | return -EINVAL; | 415 | return -EINVAL; |
420 | 416 | ||
421 | memset(f, 0, sizeof(*f)); | 417 | memset(f, 0, sizeof(*f)); |
422 | f->type = V4L2_TUNER_ANALOG_TV; | 418 | f->type = V4L2_TUNER_ANALOG_TV; |
423 | f->frequency = av7110->current_freq; | 419 | f->frequency = av7110->current_freq; |
424 | return 0; | 420 | return 0; |
425 | } | 421 | } |
426 | case VIDIOC_S_FREQUENCY: | ||
427 | { | ||
428 | struct v4l2_frequency *f = arg; | ||
429 | 422 | ||
430 | dprintk(2, "VIDIOC_S_FREQUENCY: freq:0x%08x.\n", f->frequency); | 423 | static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency *f) |
424 | { | ||
425 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
426 | struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; | ||
431 | 427 | ||
432 | if (!av7110->analog_tuner_flags || av7110->current_input != 1) | 428 | dprintk(2, "VIDIOC_S_FREQUENCY: freq:0x%08x.\n", f->frequency); |
433 | return -EINVAL; | ||
434 | 429 | ||
435 | if (V4L2_TUNER_ANALOG_TV != f->type) | 430 | if (!av7110->analog_tuner_flags || av7110->current_input != 1) |
436 | return -EINVAL; | 431 | return -EINVAL; |
437 | 432 | ||
438 | msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0xffe0); // fast mute | 433 | if (V4L2_TUNER_ANALOG_TV != f->type) |
439 | msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0xffe0); | 434 | return -EINVAL; |
440 | 435 | ||
441 | /* tune in desired frequency */ | 436 | msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0xffe0); /* fast mute */ |
442 | if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) { | 437 | msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0xffe0); |
443 | ves1820_set_tv_freq(dev, f->frequency); | ||
444 | } else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) { | ||
445 | stv0297_set_tv_freq(dev, f->frequency); | ||
446 | } | ||
447 | av7110->current_freq = f->frequency; | ||
448 | 438 | ||
449 | msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x003f); // start stereo detection | 439 | /* tune in desired frequency */ |
450 | msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x0000); | 440 | if (av7110->analog_tuner_flags & ANALOG_TUNER_VES1820) |
451 | msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); // loudspeaker + headphone | 441 | ves1820_set_tv_freq(dev, f->frequency); |
452 | msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); // SCART 1 volume | 442 | else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) |
453 | return 0; | 443 | stv0297_set_tv_freq(dev, f->frequency); |
454 | } | 444 | av7110->current_freq = f->frequency; |
455 | case VIDIOC_ENUMINPUT: | ||
456 | { | ||
457 | struct v4l2_input *i = arg; | ||
458 | 445 | ||
459 | dprintk(2, "VIDIOC_ENUMINPUT: %d\n", i->index); | 446 | msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x003f); /* start stereo detection */ |
447 | msp_writereg(av7110, MSP_WR_DSP, 0x0015, 0x0000); | ||
448 | msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x4f00); /* loudspeaker + headphone */ | ||
449 | msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x4f00); /* SCART 1 volume */ | ||
450 | return 0; | ||
451 | } | ||
460 | 452 | ||
461 | if (av7110->analog_tuner_flags) { | 453 | static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) |
462 | if (i->index < 0 || i->index >= 4) | 454 | { |
463 | return -EINVAL; | 455 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; |
464 | } else { | 456 | struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; |
465 | if (i->index != 0) | ||
466 | return -EINVAL; | ||
467 | } | ||
468 | 457 | ||
469 | memcpy(i, &inputs[i->index], sizeof(struct v4l2_input)); | 458 | dprintk(2, "VIDIOC_ENUMINPUT: %d\n", i->index); |
470 | 459 | ||
471 | return 0; | 460 | if (av7110->analog_tuner_flags) { |
461 | if (i->index < 0 || i->index >= 4) | ||
462 | return -EINVAL; | ||
463 | } else { | ||
464 | if (i->index != 0) | ||
465 | return -EINVAL; | ||
472 | } | 466 | } |
473 | case VIDIOC_G_INPUT: | 467 | |
474 | { | 468 | memcpy(i, &inputs[i->index], sizeof(struct v4l2_input)); |
475 | int *input = (int *)arg; | 469 | |
476 | *input = av7110->current_input; | 470 | return 0; |
477 | dprintk(2, "VIDIOC_G_INPUT: %d\n", *input); | 471 | } |
472 | |||
473 | static int vidioc_g_input(struct file *file, void *fh, unsigned int *input) | ||
474 | { | ||
475 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
476 | struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; | ||
477 | |||
478 | *input = av7110->current_input; | ||
479 | dprintk(2, "VIDIOC_G_INPUT: %d\n", *input); | ||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | static int vidioc_s_input(struct file *file, void *fh, unsigned int input) | ||
484 | { | ||
485 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
486 | struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; | ||
487 | |||
488 | dprintk(2, "VIDIOC_S_INPUT: %d\n", input); | ||
489 | |||
490 | if (!av7110->analog_tuner_flags) | ||
478 | return 0; | 491 | return 0; |
479 | } | ||
480 | case VIDIOC_S_INPUT: | ||
481 | { | ||
482 | int input = *(int *)arg; | ||
483 | 492 | ||
484 | dprintk(2, "VIDIOC_S_INPUT: %d\n", input); | 493 | if (input < 0 || input >= 4) |
494 | return -EINVAL; | ||
485 | 495 | ||
486 | if (!av7110->analog_tuner_flags) | 496 | av7110->current_input = input; |
487 | return 0; | 497 | return av7110_dvb_c_switch(fh); |
498 | } | ||
488 | 499 | ||
489 | if (input < 0 || input >= 4) | 500 | static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a) |
490 | return -EINVAL; | 501 | { |
502 | dprintk(2, "VIDIOC_G_AUDIO: %d\n", a->index); | ||
503 | if (a->index != 0) | ||
504 | return -EINVAL; | ||
505 | memcpy(a, &msp3400_v4l2_audio, sizeof(struct v4l2_audio)); | ||
506 | return 0; | ||
507 | } | ||
491 | 508 | ||
492 | av7110->current_input = input; | 509 | static int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a) |
493 | return av7110_dvb_c_switch(fh); | 510 | { |
494 | } | 511 | dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index); |
495 | case VIDIOC_G_AUDIO: | 512 | return 0; |
496 | { | 513 | } |
497 | struct v4l2_audio *a = arg; | ||
498 | 514 | ||
499 | dprintk(2, "VIDIOC_G_AUDIO: %d\n", a->index); | 515 | static int vidioc_g_sliced_vbi_cap(struct file *file, void *fh, |
500 | if (a->index != 0) | 516 | struct v4l2_sliced_vbi_cap *cap) |
501 | return -EINVAL; | 517 | { |
502 | memcpy(a, &msp3400_v4l2_audio, sizeof(struct v4l2_audio)); | 518 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; |
503 | break; | 519 | struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; |
504 | } | 520 | |
505 | case VIDIOC_S_AUDIO: | 521 | dprintk(2, "VIDIOC_G_SLICED_VBI_CAP\n"); |
506 | { | 522 | memset(cap, 0, sizeof(*cap)); |
507 | struct v4l2_audio *a = arg; | 523 | if (FW_VERSION(av7110->arm_app) >= 0x2623) { |
508 | dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index); | 524 | cap->service_set = V4L2_SLICED_WSS_625; |
509 | break; | 525 | cap->service_lines[0][23] = V4L2_SLICED_WSS_625; |
510 | } | ||
511 | case VIDIOC_G_SLICED_VBI_CAP: | ||
512 | { | ||
513 | struct v4l2_sliced_vbi_cap *cap = arg; | ||
514 | dprintk(2, "VIDIOC_G_SLICED_VBI_CAP\n"); | ||
515 | memset(cap, 0, sizeof *cap); | ||
516 | if (FW_VERSION(av7110->arm_app) >= 0x2623) { | ||
517 | cap->service_set = V4L2_SLICED_WSS_625; | ||
518 | cap->service_lines[0][23] = V4L2_SLICED_WSS_625; | ||
519 | } | ||
520 | break; | ||
521 | } | ||
522 | case VIDIOC_G_FMT: | ||
523 | { | ||
524 | struct v4l2_format *f = arg; | ||
525 | dprintk(2, "VIDIOC_G_FMT:\n"); | ||
526 | if (f->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT || | ||
527 | FW_VERSION(av7110->arm_app) < 0x2623) | ||
528 | return -EAGAIN; /* handled by core driver */ | ||
529 | memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced); | ||
530 | if (av7110->wssMode) { | ||
531 | f->fmt.sliced.service_set = V4L2_SLICED_WSS_625; | ||
532 | f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625; | ||
533 | f->fmt.sliced.io_size = sizeof (struct v4l2_sliced_vbi_data); | ||
534 | } | ||
535 | break; | ||
536 | } | 526 | } |
537 | case VIDIOC_S_FMT: | 527 | return 0; |
538 | { | 528 | } |
539 | struct v4l2_format *f = arg; | 529 | |
540 | dprintk(2, "VIDIOC_S_FMT\n"); | 530 | static int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh, |
541 | if (f->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT || | 531 | struct v4l2_format *f) |
542 | FW_VERSION(av7110->arm_app) < 0x2623) | 532 | { |
543 | return -EAGAIN; /* handled by core driver */ | 533 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; |
544 | if (f->fmt.sliced.service_set != V4L2_SLICED_WSS_625 && | 534 | struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; |
545 | f->fmt.sliced.service_lines[0][23] != V4L2_SLICED_WSS_625) { | 535 | |
546 | memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced); | 536 | dprintk(2, "VIDIOC_G_FMT:\n"); |
547 | /* WSS controlled by firmware */ | 537 | if (FW_VERSION(av7110->arm_app) < 0x2623) |
548 | av7110->wssMode = 0; | 538 | return -EINVAL; |
549 | av7110->wssData = 0; | 539 | memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced); |
550 | return av7110_fw_cmd(av7110, COMTYPE_ENCODER, | 540 | if (av7110->wssMode) { |
551 | SetWSSConfig, 1, 0); | 541 | f->fmt.sliced.service_set = V4L2_SLICED_WSS_625; |
552 | } else { | 542 | f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625; |
553 | memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced); | 543 | f->fmt.sliced.io_size = sizeof(struct v4l2_sliced_vbi_data); |
554 | f->fmt.sliced.service_set = V4L2_SLICED_WSS_625; | ||
555 | f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625; | ||
556 | f->fmt.sliced.io_size = sizeof (struct v4l2_sliced_vbi_data); | ||
557 | /* WSS controlled by userspace */ | ||
558 | av7110->wssMode = 1; | ||
559 | av7110->wssData = 0; | ||
560 | } | ||
561 | break; | ||
562 | } | 544 | } |
563 | default: | 545 | return 0; |
564 | printk("no such ioctl\n"); | 546 | } |
565 | return -ENOIOCTLCMD; | 547 | |
548 | static int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *fh, | ||
549 | struct v4l2_format *f) | ||
550 | { | ||
551 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
552 | struct av7110 *av7110 = (struct av7110 *)dev->ext_priv; | ||
553 | |||
554 | dprintk(2, "VIDIOC_S_FMT\n"); | ||
555 | if (FW_VERSION(av7110->arm_app) < 0x2623) | ||
556 | return -EINVAL; | ||
557 | if (f->fmt.sliced.service_set != V4L2_SLICED_WSS_625 && | ||
558 | f->fmt.sliced.service_lines[0][23] != V4L2_SLICED_WSS_625) { | ||
559 | memset(&f->fmt.sliced, 0, sizeof(f->fmt.sliced)); | ||
560 | /* WSS controlled by firmware */ | ||
561 | av7110->wssMode = 0; | ||
562 | av7110->wssData = 0; | ||
563 | return av7110_fw_cmd(av7110, COMTYPE_ENCODER, | ||
564 | SetWSSConfig, 1, 0); | ||
565 | } else { | ||
566 | memset(&f->fmt.sliced, 0, sizeof(f->fmt.sliced)); | ||
567 | f->fmt.sliced.service_set = V4L2_SLICED_WSS_625; | ||
568 | f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625; | ||
569 | f->fmt.sliced.io_size = sizeof(struct v4l2_sliced_vbi_data); | ||
570 | /* WSS controlled by userspace */ | ||
571 | av7110->wssMode = 1; | ||
572 | av7110->wssData = 0; | ||
566 | } | 573 | } |
567 | return 0; | 574 | return 0; |
568 | } | 575 | } |
@@ -609,22 +616,6 @@ static ssize_t av7110_vbi_write(struct file *file, const char __user *data, size | |||
609 | * INITIALIZATION | 616 | * INITIALIZATION |
610 | ****************************************************************************/ | 617 | ****************************************************************************/ |
611 | 618 | ||
612 | static struct saa7146_extension_ioctls ioctls[] = { | ||
613 | { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE }, | ||
614 | { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE }, | ||
615 | { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE }, | ||
616 | { VIDIOC_G_FREQUENCY, SAA7146_EXCLUSIVE }, | ||
617 | { VIDIOC_S_FREQUENCY, SAA7146_EXCLUSIVE }, | ||
618 | { VIDIOC_G_TUNER, SAA7146_EXCLUSIVE }, | ||
619 | { VIDIOC_S_TUNER, SAA7146_EXCLUSIVE }, | ||
620 | { VIDIOC_G_AUDIO, SAA7146_EXCLUSIVE }, | ||
621 | { VIDIOC_S_AUDIO, SAA7146_EXCLUSIVE }, | ||
622 | { VIDIOC_G_SLICED_VBI_CAP, SAA7146_EXCLUSIVE }, | ||
623 | { VIDIOC_G_FMT, SAA7146_BEFORE }, | ||
624 | { VIDIOC_S_FMT, SAA7146_BEFORE }, | ||
625 | { 0, 0 } | ||
626 | }; | ||
627 | |||
628 | static u8 saa7113_init_regs[] = { | 619 | static u8 saa7113_init_regs[] = { |
629 | 0x02, 0xd0, | 620 | 0x02, 0xd0, |
630 | 0x03, 0x23, | 621 | 0x03, 0x23, |
@@ -788,20 +779,34 @@ int av7110_init_analog_module(struct av7110 *av7110) | |||
788 | int av7110_init_v4l(struct av7110 *av7110) | 779 | int av7110_init_v4l(struct av7110 *av7110) |
789 | { | 780 | { |
790 | struct saa7146_dev* dev = av7110->dev; | 781 | struct saa7146_dev* dev = av7110->dev; |
782 | struct saa7146_ext_vv *vv_data; | ||
791 | int ret; | 783 | int ret; |
792 | 784 | ||
793 | /* special case DVB-C: these cards have an analog tuner | 785 | /* special case DVB-C: these cards have an analog tuner |
794 | plus need some special handling, so we have separate | 786 | plus need some special handling, so we have separate |
795 | saa7146_ext_vv data for these... */ | 787 | saa7146_ext_vv data for these... */ |
796 | if (av7110->analog_tuner_flags) | 788 | if (av7110->analog_tuner_flags) |
797 | ret = saa7146_vv_init(dev, &av7110_vv_data_c); | 789 | vv_data = &av7110_vv_data_c; |
798 | else | 790 | else |
799 | ret = saa7146_vv_init(dev, &av7110_vv_data_st); | 791 | vv_data = &av7110_vv_data_st; |
792 | ret = saa7146_vv_init(dev, vv_data); | ||
800 | 793 | ||
801 | if (ret) { | 794 | if (ret) { |
802 | ERR(("cannot init capture device. skipping.\n")); | 795 | ERR(("cannot init capture device. skipping.\n")); |
803 | return -ENODEV; | 796 | return -ENODEV; |
804 | } | 797 | } |
798 | vv_data->ops.vidioc_enum_input = vidioc_enum_input; | ||
799 | vv_data->ops.vidioc_g_input = vidioc_g_input; | ||
800 | vv_data->ops.vidioc_s_input = vidioc_s_input; | ||
801 | vv_data->ops.vidioc_g_tuner = vidioc_g_tuner; | ||
802 | vv_data->ops.vidioc_s_tuner = vidioc_s_tuner; | ||
803 | vv_data->ops.vidioc_g_frequency = vidioc_g_frequency; | ||
804 | vv_data->ops.vidioc_s_frequency = vidioc_s_frequency; | ||
805 | vv_data->ops.vidioc_g_audio = vidioc_g_audio; | ||
806 | vv_data->ops.vidioc_s_audio = vidioc_s_audio; | ||
807 | vv_data->ops.vidioc_g_sliced_vbi_cap = vidioc_g_sliced_vbi_cap; | ||
808 | vv_data->ops.vidioc_g_fmt_sliced_vbi_out = vidioc_g_fmt_sliced_vbi_out; | ||
809 | vv_data->ops.vidioc_s_fmt_sliced_vbi_out = vidioc_s_fmt_sliced_vbi_out; | ||
805 | 810 | ||
806 | if (saa7146_register_device(&av7110->v4l_dev, dev, "av7110", VFL_TYPE_GRABBER)) { | 811 | if (saa7146_register_device(&av7110->v4l_dev, dev, "av7110", VFL_TYPE_GRABBER)) { |
807 | ERR(("cannot register capture device. skipping.\n")); | 812 | ERR(("cannot register capture device. skipping.\n")); |
@@ -900,9 +905,6 @@ static struct saa7146_ext_vv av7110_vv_data_st = { | |||
900 | .num_stds = ARRAY_SIZE(standard), | 905 | .num_stds = ARRAY_SIZE(standard), |
901 | .std_callback = &std_callback, | 906 | .std_callback = &std_callback, |
902 | 907 | ||
903 | .ioctls = &ioctls[0], | ||
904 | .ioctl = av7110_ioctl, | ||
905 | |||
906 | .vbi_fops.open = av7110_vbi_reset, | 908 | .vbi_fops.open = av7110_vbi_reset, |
907 | .vbi_fops.release = av7110_vbi_reset, | 909 | .vbi_fops.release = av7110_vbi_reset, |
908 | .vbi_fops.write = av7110_vbi_write, | 910 | .vbi_fops.write = av7110_vbi_write, |
@@ -918,9 +920,6 @@ static struct saa7146_ext_vv av7110_vv_data_c = { | |||
918 | .num_stds = ARRAY_SIZE(standard), | 920 | .num_stds = ARRAY_SIZE(standard), |
919 | .std_callback = &std_callback, | 921 | .std_callback = &std_callback, |
920 | 922 | ||
921 | .ioctls = &ioctls[0], | ||
922 | .ioctl = av7110_ioctl, | ||
923 | |||
924 | .vbi_fops.open = av7110_vbi_reset, | 923 | .vbi_fops.open = av7110_vbi_reset, |
925 | .vbi_fops.release = av7110_vbi_reset, | 924 | .vbi_fops.release = av7110_vbi_reset, |
926 | .vbi_fops.write = av7110_vbi_write, | 925 | .vbi_fops.write = av7110_vbi_write, |
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 4182121d7e5d..855fe74b640b 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c | |||
@@ -1404,6 +1404,41 @@ static int budget_av_detach(struct saa7146_dev *dev) | |||
1404 | return err; | 1404 | return err; |
1405 | } | 1405 | } |
1406 | 1406 | ||
1407 | #define KNC1_INPUTS 2 | ||
1408 | static struct v4l2_input knc1_inputs[KNC1_INPUTS] = { | ||
1409 | {0, "Composite", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0}, | ||
1410 | {1, "S-Video", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0}, | ||
1411 | }; | ||
1412 | |||
1413 | static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) | ||
1414 | { | ||
1415 | dprintk(1, "VIDIOC_ENUMINPUT %d.\n", i->index); | ||
1416 | if (i->index < 0 || i->index >= KNC1_INPUTS) | ||
1417 | return -EINVAL; | ||
1418 | memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input)); | ||
1419 | return 0; | ||
1420 | } | ||
1421 | |||
1422 | static int vidioc_g_input(struct file *file, void *fh, unsigned int *i) | ||
1423 | { | ||
1424 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
1425 | struct budget_av *budget_av = (struct budget_av *)dev->ext_priv; | ||
1426 | |||
1427 | *i = budget_av->cur_input; | ||
1428 | |||
1429 | dprintk(1, "VIDIOC_G_INPUT %d.\n", *i); | ||
1430 | return 0; | ||
1431 | } | ||
1432 | |||
1433 | static int vidioc_s_input(struct file *file, void *fh, unsigned int input) | ||
1434 | { | ||
1435 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
1436 | struct budget_av *budget_av = (struct budget_av *)dev->ext_priv; | ||
1437 | |||
1438 | dprintk(1, "VIDIOC_S_INPUT %d.\n", input); | ||
1439 | return saa7113_setinput(budget_av, input); | ||
1440 | } | ||
1441 | |||
1407 | static struct saa7146_ext_vv vv_data; | 1442 | static struct saa7146_ext_vv vv_data; |
1408 | 1443 | ||
1409 | static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) | 1444 | static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) |
@@ -1442,6 +1477,9 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio | |||
1442 | ERR(("cannot init vv subsystem.\n")); | 1477 | ERR(("cannot init vv subsystem.\n")); |
1443 | return err; | 1478 | return err; |
1444 | } | 1479 | } |
1480 | vv_data.ops.vidioc_enum_input = vidioc_enum_input; | ||
1481 | vv_data.ops.vidioc_g_input = vidioc_g_input; | ||
1482 | vv_data.ops.vidioc_s_input = vidioc_s_input; | ||
1445 | 1483 | ||
1446 | if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) { | 1484 | if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) { |
1447 | /* fixme: proper cleanup here */ | 1485 | /* fixme: proper cleanup here */ |
@@ -1480,54 +1518,6 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio | |||
1480 | return 0; | 1518 | return 0; |
1481 | } | 1519 | } |
1482 | 1520 | ||
1483 | #define KNC1_INPUTS 2 | ||
1484 | static struct v4l2_input knc1_inputs[KNC1_INPUTS] = { | ||
1485 | {0, "Composite", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0}, | ||
1486 | {1, "S-Video", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0}, | ||
1487 | }; | ||
1488 | |||
1489 | static struct saa7146_extension_ioctls ioctls[] = { | ||
1490 | {VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE}, | ||
1491 | {VIDIOC_G_INPUT, SAA7146_EXCLUSIVE}, | ||
1492 | {VIDIOC_S_INPUT, SAA7146_EXCLUSIVE}, | ||
1493 | {0, 0} | ||
1494 | }; | ||
1495 | |||
1496 | static long av_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) | ||
1497 | { | ||
1498 | struct saa7146_dev *dev = fh->dev; | ||
1499 | struct budget_av *budget_av = (struct budget_av *) dev->ext_priv; | ||
1500 | |||
1501 | switch (cmd) { | ||
1502 | case VIDIOC_ENUMINPUT:{ | ||
1503 | struct v4l2_input *i = arg; | ||
1504 | |||
1505 | dprintk(1, "VIDIOC_ENUMINPUT %d.\n", i->index); | ||
1506 | if (i->index < 0 || i->index >= KNC1_INPUTS) { | ||
1507 | return -EINVAL; | ||
1508 | } | ||
1509 | memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input)); | ||
1510 | return 0; | ||
1511 | } | ||
1512 | case VIDIOC_G_INPUT:{ | ||
1513 | int *input = (int *) arg; | ||
1514 | |||
1515 | *input = budget_av->cur_input; | ||
1516 | |||
1517 | dprintk(1, "VIDIOC_G_INPUT %d.\n", *input); | ||
1518 | return 0; | ||
1519 | } | ||
1520 | case VIDIOC_S_INPUT:{ | ||
1521 | int input = *(int *) arg; | ||
1522 | dprintk(1, "VIDIOC_S_INPUT %d.\n", input); | ||
1523 | return saa7113_setinput(budget_av, input); | ||
1524 | } | ||
1525 | default: | ||
1526 | return -ENOIOCTLCMD; | ||
1527 | } | ||
1528 | return 0; | ||
1529 | } | ||
1530 | |||
1531 | static struct saa7146_standard standard[] = { | 1521 | static struct saa7146_standard standard[] = { |
1532 | {.name = "PAL",.id = V4L2_STD_PAL, | 1522 | {.name = "PAL",.id = V4L2_STD_PAL, |
1533 | .v_offset = 0x17,.v_field = 288, | 1523 | .v_offset = 0x17,.v_field = 288, |
@@ -1546,8 +1536,6 @@ static struct saa7146_ext_vv vv_data = { | |||
1546 | .flags = 0, | 1536 | .flags = 0, |
1547 | .stds = &standard[0], | 1537 | .stds = &standard[0], |
1548 | .num_stds = ARRAY_SIZE(standard), | 1538 | .num_stds = ARRAY_SIZE(standard), |
1549 | .ioctls = &ioctls[0], | ||
1550 | .ioctl = av_ioctl, | ||
1551 | }; | 1539 | }; |
1552 | 1540 | ||
1553 | static struct saa7146_extension budget_extension; | 1541 | static struct saa7146_extension budget_extension; |
diff --git a/drivers/media/video/hexium_gemini.c b/drivers/media/video/hexium_gemini.c index 79393d1772e4..8e1463ee1b64 100644 --- a/drivers/media/video/hexium_gemini.c +++ b/drivers/media/video/hexium_gemini.c | |||
@@ -56,17 +56,6 @@ struct hexium_data | |||
56 | u8 byte; | 56 | u8 byte; |
57 | }; | 57 | }; |
58 | 58 | ||
59 | static struct saa7146_extension_ioctls ioctls[] = { | ||
60 | { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE }, | ||
61 | { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE }, | ||
62 | { VIDIOC_QUERYCTRL, SAA7146_BEFORE }, | ||
63 | { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE }, | ||
64 | { VIDIOC_S_STD, SAA7146_AFTER }, | ||
65 | { VIDIOC_G_CTRL, SAA7146_BEFORE }, | ||
66 | { VIDIOC_S_CTRL, SAA7146_BEFORE }, | ||
67 | { 0, 0 } | ||
68 | }; | ||
69 | |||
70 | #define HEXIUM_CONTROLS 1 | 59 | #define HEXIUM_CONTROLS 1 |
71 | static struct v4l2_queryctrl hexium_controls[] = { | 60 | static struct v4l2_queryctrl hexium_controls[] = { |
72 | { V4L2_CID_PRIVATE_BASE, V4L2_CTRL_TYPE_BOOLEAN, "B/W", 0, 1, 1, 0, 0 }, | 61 | { V4L2_CID_PRIVATE_BASE, V4L2_CTRL_TYPE_BOOLEAN, "B/W", 0, 1, 1, 0, 0 }, |
@@ -231,6 +220,132 @@ static int hexium_set_standard(struct hexium *hexium, struct hexium_data *vdec) | |||
231 | return 0; | 220 | return 0; |
232 | } | 221 | } |
233 | 222 | ||
223 | static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) | ||
224 | { | ||
225 | DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index)); | ||
226 | |||
227 | if (i->index < 0 || i->index >= HEXIUM_INPUTS) | ||
228 | return -EINVAL; | ||
229 | |||
230 | memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input)); | ||
231 | |||
232 | DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index)); | ||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | static int vidioc_g_input(struct file *file, void *fh, unsigned int *input) | ||
237 | { | ||
238 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
239 | struct hexium *hexium = (struct hexium *) dev->ext_priv; | ||
240 | |||
241 | *input = hexium->cur_input; | ||
242 | |||
243 | DEB_D(("VIDIOC_G_INPUT: %d\n", *input)); | ||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | static int vidioc_s_input(struct file *file, void *fh, unsigned int input) | ||
248 | { | ||
249 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
250 | struct hexium *hexium = (struct hexium *) dev->ext_priv; | ||
251 | |||
252 | DEB_EE(("VIDIOC_S_INPUT %d.\n", input)); | ||
253 | |||
254 | if (input < 0 || input >= HEXIUM_INPUTS) | ||
255 | return -EINVAL; | ||
256 | |||
257 | hexium->cur_input = input; | ||
258 | hexium_set_input(hexium, input); | ||
259 | return 0; | ||
260 | } | ||
261 | |||
262 | /* the saa7146 provides some controls (brightness, contrast, saturation) | ||
263 | which gets registered *after* this function. because of this we have | ||
264 | to return with a value != 0 even if the function succeded.. */ | ||
265 | static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qc) | ||
266 | { | ||
267 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
268 | int i; | ||
269 | |||
270 | for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) { | ||
271 | if (hexium_controls[i].id == qc->id) { | ||
272 | *qc = hexium_controls[i]; | ||
273 | DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id)); | ||
274 | return 0; | ||
275 | } | ||
276 | } | ||
277 | return dev->ext_vv_data->core_ops->vidioc_queryctrl(file, fh, qc); | ||
278 | } | ||
279 | |||
280 | static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *vc) | ||
281 | { | ||
282 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
283 | struct hexium *hexium = (struct hexium *) dev->ext_priv; | ||
284 | int i; | ||
285 | |||
286 | for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) { | ||
287 | if (hexium_controls[i].id == vc->id) | ||
288 | break; | ||
289 | } | ||
290 | |||
291 | if (i < 0) | ||
292 | return dev->ext_vv_data->core_ops->vidioc_g_ctrl(file, fh, vc); | ||
293 | |||
294 | if (vc->id == V4L2_CID_PRIVATE_BASE) { | ||
295 | vc->value = hexium->cur_bw; | ||
296 | DEB_D(("VIDIOC_G_CTRL BW:%d.\n", vc->value)); | ||
297 | return 0; | ||
298 | } | ||
299 | return -EINVAL; | ||
300 | } | ||
301 | |||
302 | static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *vc) | ||
303 | { | ||
304 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
305 | struct hexium *hexium = (struct hexium *) dev->ext_priv; | ||
306 | int i = 0; | ||
307 | |||
308 | for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) { | ||
309 | if (hexium_controls[i].id == vc->id) | ||
310 | break; | ||
311 | } | ||
312 | |||
313 | if (i < 0) | ||
314 | return dev->ext_vv_data->core_ops->vidioc_s_ctrl(file, fh, vc); | ||
315 | |||
316 | if (vc->id == V4L2_CID_PRIVATE_BASE) | ||
317 | hexium->cur_bw = vc->value; | ||
318 | |||
319 | DEB_D(("VIDIOC_S_CTRL BW:%d.\n", hexium->cur_bw)); | ||
320 | |||
321 | if (0 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) { | ||
322 | hexium_set_standard(hexium, hexium_pal); | ||
323 | return 0; | ||
324 | } | ||
325 | if (0 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) { | ||
326 | hexium_set_standard(hexium, hexium_ntsc); | ||
327 | return 0; | ||
328 | } | ||
329 | if (0 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) { | ||
330 | hexium_set_standard(hexium, hexium_secam); | ||
331 | return 0; | ||
332 | } | ||
333 | if (1 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) { | ||
334 | hexium_set_standard(hexium, hexium_pal_bw); | ||
335 | return 0; | ||
336 | } | ||
337 | if (1 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) { | ||
338 | hexium_set_standard(hexium, hexium_ntsc_bw); | ||
339 | return 0; | ||
340 | } | ||
341 | if (1 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) | ||
342 | /* fixme: is there no bw secam mode? */ | ||
343 | return -EINVAL; | ||
344 | |||
345 | return -EINVAL; | ||
346 | } | ||
347 | |||
348 | |||
234 | static struct saa7146_ext_vv vv_data; | 349 | static struct saa7146_ext_vv vv_data; |
235 | 350 | ||
236 | /* this function only gets called when the probing was successful */ | 351 | /* this function only gets called when the probing was successful */ |
@@ -279,6 +394,12 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d | |||
279 | hexium->cur_input = 0; | 394 | hexium->cur_input = 0; |
280 | 395 | ||
281 | saa7146_vv_init(dev, &vv_data); | 396 | saa7146_vv_init(dev, &vv_data); |
397 | vv_data.ops.vidioc_queryctrl = vidioc_queryctrl; | ||
398 | vv_data.ops.vidioc_g_ctrl = vidioc_g_ctrl; | ||
399 | vv_data.ops.vidioc_s_ctrl = vidioc_s_ctrl; | ||
400 | vv_data.ops.vidioc_enum_input = vidioc_enum_input; | ||
401 | vv_data.ops.vidioc_g_input = vidioc_g_input; | ||
402 | vv_data.ops.vidioc_s_input = vidioc_s_input; | ||
282 | if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER)) { | 403 | if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER)) { |
283 | printk("hexium_gemini: cannot register capture v4l2 device. skipping.\n"); | 404 | printk("hexium_gemini: cannot register capture v4l2 device. skipping.\n"); |
284 | return -1; | 405 | return -1; |
@@ -306,153 +427,6 @@ static int hexium_detach(struct saa7146_dev *dev) | |||
306 | return 0; | 427 | return 0; |
307 | } | 428 | } |
308 | 429 | ||
309 | static long hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) | ||
310 | { | ||
311 | struct saa7146_dev *dev = fh->dev; | ||
312 | struct hexium *hexium = (struct hexium *) dev->ext_priv; | ||
313 | /* | ||
314 | struct saa7146_vv *vv = dev->vv_data; | ||
315 | */ | ||
316 | switch (cmd) { | ||
317 | case VIDIOC_ENUMINPUT: | ||
318 | { | ||
319 | struct v4l2_input *i = arg; | ||
320 | DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index)); | ||
321 | |||
322 | if (i->index < 0 || i->index >= HEXIUM_INPUTS) { | ||
323 | return -EINVAL; | ||
324 | } | ||
325 | |||
326 | memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input)); | ||
327 | |||
328 | DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index)); | ||
329 | return 0; | ||
330 | } | ||
331 | case VIDIOC_G_INPUT: | ||
332 | { | ||
333 | int *input = (int *) arg; | ||
334 | *input = hexium->cur_input; | ||
335 | |||
336 | DEB_D(("VIDIOC_G_INPUT: %d\n", *input)); | ||
337 | return 0; | ||
338 | } | ||
339 | case VIDIOC_S_INPUT: | ||
340 | { | ||
341 | int input = *(int *) arg; | ||
342 | |||
343 | DEB_EE(("VIDIOC_S_INPUT %d.\n", input)); | ||
344 | |||
345 | if (input < 0 || input >= HEXIUM_INPUTS) { | ||
346 | return -EINVAL; | ||
347 | } | ||
348 | |||
349 | hexium->cur_input = input; | ||
350 | hexium_set_input(hexium, input); | ||
351 | |||
352 | return 0; | ||
353 | } | ||
354 | /* the saa7146 provides some controls (brightness, contrast, saturation) | ||
355 | which gets registered *after* this function. because of this we have | ||
356 | to return with a value != 0 even if the function succeded.. */ | ||
357 | case VIDIOC_QUERYCTRL: | ||
358 | { | ||
359 | struct v4l2_queryctrl *qc = arg; | ||
360 | int i; | ||
361 | |||
362 | for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) { | ||
363 | if (hexium_controls[i].id == qc->id) { | ||
364 | *qc = hexium_controls[i]; | ||
365 | DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id)); | ||
366 | return 0; | ||
367 | } | ||
368 | } | ||
369 | return -EAGAIN; | ||
370 | } | ||
371 | case VIDIOC_G_CTRL: | ||
372 | { | ||
373 | struct v4l2_control *vc = arg; | ||
374 | int i; | ||
375 | |||
376 | for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) { | ||
377 | if (hexium_controls[i].id == vc->id) { | ||
378 | break; | ||
379 | } | ||
380 | } | ||
381 | |||
382 | if (i < 0) { | ||
383 | return -EAGAIN; | ||
384 | } | ||
385 | |||
386 | switch (vc->id) { | ||
387 | case V4L2_CID_PRIVATE_BASE:{ | ||
388 | vc->value = hexium->cur_bw; | ||
389 | DEB_D(("VIDIOC_G_CTRL BW:%d.\n", vc->value)); | ||
390 | return 0; | ||
391 | } | ||
392 | } | ||
393 | return -EINVAL; | ||
394 | } | ||
395 | |||
396 | case VIDIOC_S_CTRL: | ||
397 | { | ||
398 | struct v4l2_control *vc = arg; | ||
399 | int i = 0; | ||
400 | |||
401 | for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) { | ||
402 | if (hexium_controls[i].id == vc->id) { | ||
403 | break; | ||
404 | } | ||
405 | } | ||
406 | |||
407 | if (i < 0) { | ||
408 | return -EAGAIN; | ||
409 | } | ||
410 | |||
411 | switch (vc->id) { | ||
412 | case V4L2_CID_PRIVATE_BASE:{ | ||
413 | hexium->cur_bw = vc->value; | ||
414 | break; | ||
415 | } | ||
416 | } | ||
417 | |||
418 | DEB_D(("VIDIOC_S_CTRL BW:%d.\n", hexium->cur_bw)); | ||
419 | |||
420 | if (0 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) { | ||
421 | hexium_set_standard(hexium, hexium_pal); | ||
422 | return 0; | ||
423 | } | ||
424 | if (0 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) { | ||
425 | hexium_set_standard(hexium, hexium_ntsc); | ||
426 | return 0; | ||
427 | } | ||
428 | if (0 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) { | ||
429 | hexium_set_standard(hexium, hexium_secam); | ||
430 | return 0; | ||
431 | } | ||
432 | if (1 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) { | ||
433 | hexium_set_standard(hexium, hexium_pal_bw); | ||
434 | return 0; | ||
435 | } | ||
436 | if (1 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) { | ||
437 | hexium_set_standard(hexium, hexium_ntsc_bw); | ||
438 | return 0; | ||
439 | } | ||
440 | if (1 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) { | ||
441 | /* fixme: is there no bw secam mode? */ | ||
442 | return -EINVAL; | ||
443 | } | ||
444 | |||
445 | return -EINVAL; | ||
446 | } | ||
447 | default: | ||
448 | /* | ||
449 | DEB_D(("hexium_ioctl() does not handle this ioctl.\n")); | ||
450 | */ | ||
451 | return -ENOIOCTLCMD; | ||
452 | } | ||
453 | return 0; | ||
454 | } | ||
455 | |||
456 | static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std) | 430 | static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std) |
457 | { | 431 | { |
458 | struct hexium *hexium = (struct hexium *) dev->ext_priv; | 432 | struct hexium *hexium = (struct hexium *) dev->ext_priv; |
@@ -514,8 +488,6 @@ static struct saa7146_ext_vv vv_data = { | |||
514 | .stds = &hexium_standards[0], | 488 | .stds = &hexium_standards[0], |
515 | .num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard), | 489 | .num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard), |
516 | .std_callback = &std_callback, | 490 | .std_callback = &std_callback, |
517 | .ioctls = &ioctls[0], | ||
518 | .ioctl = hexium_ioctl, | ||
519 | }; | 491 | }; |
520 | 492 | ||
521 | static struct saa7146_extension hexium_extension = { | 493 | static struct saa7146_extension hexium_extension = { |
diff --git a/drivers/media/video/hexium_orion.c b/drivers/media/video/hexium_orion.c index 074bec711fe0..2bc39f628455 100644 --- a/drivers/media/video/hexium_orion.c +++ b/drivers/media/video/hexium_orion.c | |||
@@ -57,14 +57,6 @@ struct hexium_data | |||
57 | u8 byte; | 57 | u8 byte; |
58 | }; | 58 | }; |
59 | 59 | ||
60 | static struct saa7146_extension_ioctls ioctls[] = { | ||
61 | { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE }, | ||
62 | { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE }, | ||
63 | { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE }, | ||
64 | { VIDIOC_S_STD, SAA7146_AFTER }, | ||
65 | { 0, 0 } | ||
66 | }; | ||
67 | |||
68 | struct hexium | 60 | struct hexium |
69 | { | 61 | { |
70 | int type; | 62 | int type; |
@@ -329,6 +321,44 @@ static int hexium_set_input(struct hexium *hexium, int input) | |||
329 | return 0; | 321 | return 0; |
330 | } | 322 | } |
331 | 323 | ||
324 | static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) | ||
325 | { | ||
326 | DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index)); | ||
327 | |||
328 | if (i->index < 0 || i->index >= HEXIUM_INPUTS) | ||
329 | return -EINVAL; | ||
330 | |||
331 | memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input)); | ||
332 | |||
333 | DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index)); | ||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | static int vidioc_g_input(struct file *file, void *fh, unsigned int *input) | ||
338 | { | ||
339 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
340 | struct hexium *hexium = (struct hexium *) dev->ext_priv; | ||
341 | |||
342 | *input = hexium->cur_input; | ||
343 | |||
344 | DEB_D(("VIDIOC_G_INPUT: %d\n", *input)); | ||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | static int vidioc_s_input(struct file *file, void *fh, unsigned int input) | ||
349 | { | ||
350 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
351 | struct hexium *hexium = (struct hexium *) dev->ext_priv; | ||
352 | |||
353 | if (input < 0 || input >= HEXIUM_INPUTS) | ||
354 | return -EINVAL; | ||
355 | |||
356 | hexium->cur_input = input; | ||
357 | hexium_set_input(hexium, input); | ||
358 | |||
359 | return 0; | ||
360 | } | ||
361 | |||
332 | static struct saa7146_ext_vv vv_data; | 362 | static struct saa7146_ext_vv vv_data; |
333 | 363 | ||
334 | /* this function only gets called when the probing was successful */ | 364 | /* this function only gets called when the probing was successful */ |
@@ -339,6 +369,9 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d | |||
339 | DEB_EE((".\n")); | 369 | DEB_EE((".\n")); |
340 | 370 | ||
341 | saa7146_vv_init(dev, &vv_data); | 371 | saa7146_vv_init(dev, &vv_data); |
372 | vv_data.ops.vidioc_enum_input = vidioc_enum_input; | ||
373 | vv_data.ops.vidioc_g_input = vidioc_g_input; | ||
374 | vv_data.ops.vidioc_s_input = vidioc_s_input; | ||
342 | if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_GRABBER)) { | 375 | if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_GRABBER)) { |
343 | printk("hexium_orion: cannot register capture v4l2 device. skipping.\n"); | 376 | printk("hexium_orion: cannot register capture v4l2 device. skipping.\n"); |
344 | return -1; | 377 | return -1; |
@@ -370,58 +403,6 @@ static int hexium_detach(struct saa7146_dev *dev) | |||
370 | return 0; | 403 | return 0; |
371 | } | 404 | } |
372 | 405 | ||
373 | static long hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) | ||
374 | { | ||
375 | struct saa7146_dev *dev = fh->dev; | ||
376 | struct hexium *hexium = (struct hexium *) dev->ext_priv; | ||
377 | /* | ||
378 | struct saa7146_vv *vv = dev->vv_data; | ||
379 | */ | ||
380 | switch (cmd) { | ||
381 | case VIDIOC_ENUMINPUT: | ||
382 | { | ||
383 | struct v4l2_input *i = arg; | ||
384 | DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index)); | ||
385 | |||
386 | if (i->index < 0 || i->index >= HEXIUM_INPUTS) { | ||
387 | return -EINVAL; | ||
388 | } | ||
389 | |||
390 | memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input)); | ||
391 | |||
392 | DEB_D(("v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n", i->index)); | ||
393 | return 0; | ||
394 | } | ||
395 | case VIDIOC_G_INPUT: | ||
396 | { | ||
397 | int *input = (int *) arg; | ||
398 | *input = hexium->cur_input; | ||
399 | |||
400 | DEB_D(("VIDIOC_G_INPUT: %d\n", *input)); | ||
401 | return 0; | ||
402 | } | ||
403 | case VIDIOC_S_INPUT: | ||
404 | { | ||
405 | int input = *(int *) arg; | ||
406 | |||
407 | if (input < 0 || input >= HEXIUM_INPUTS) { | ||
408 | return -EINVAL; | ||
409 | } | ||
410 | |||
411 | hexium->cur_input = input; | ||
412 | hexium_set_input(hexium, input); | ||
413 | |||
414 | return 0; | ||
415 | } | ||
416 | default: | ||
417 | /* | ||
418 | DEB_D(("hexium_ioctl() does not handle this ioctl.\n")); | ||
419 | */ | ||
420 | return -ENOIOCTLCMD; | ||
421 | } | ||
422 | return 0; | ||
423 | } | ||
424 | |||
425 | static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std) | 406 | static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std) |
426 | { | 407 | { |
427 | return 0; | 408 | return 0; |
@@ -479,8 +460,6 @@ static struct saa7146_ext_vv vv_data = { | |||
479 | .stds = &hexium_standards[0], | 460 | .stds = &hexium_standards[0], |
480 | .num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard), | 461 | .num_stds = sizeof(hexium_standards) / sizeof(struct saa7146_standard), |
481 | .std_callback = &std_callback, | 462 | .std_callback = &std_callback, |
482 | .ioctls = &ioctls[0], | ||
483 | .ioctl = hexium_ioctl, | ||
484 | }; | 463 | }; |
485 | 464 | ||
486 | static struct saa7146_extension extension = { | 465 | static struct saa7146_extension extension = { |
diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c index e3cbe14c349a..8ecda8dfbd04 100644 --- a/drivers/media/video/mxb.c +++ b/drivers/media/video/mxb.c | |||
@@ -110,26 +110,6 @@ static struct v4l2_queryctrl mxb_controls[] = { | |||
110 | { V4L2_CID_AUDIO_MUTE, V4L2_CTRL_TYPE_BOOLEAN, "Mute", 0, 1, 1, 0, 0 }, | 110 | { V4L2_CID_AUDIO_MUTE, V4L2_CTRL_TYPE_BOOLEAN, "Mute", 0, 1, 1, 0, 0 }, |
111 | }; | 111 | }; |
112 | 112 | ||
113 | static struct saa7146_extension_ioctls ioctls[] = { | ||
114 | { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE }, | ||
115 | { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE }, | ||
116 | { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE }, | ||
117 | { VIDIOC_QUERYCTRL, SAA7146_BEFORE }, | ||
118 | { VIDIOC_G_CTRL, SAA7146_BEFORE }, | ||
119 | { VIDIOC_S_CTRL, SAA7146_BEFORE }, | ||
120 | { VIDIOC_G_TUNER, SAA7146_EXCLUSIVE }, | ||
121 | { VIDIOC_S_TUNER, SAA7146_EXCLUSIVE }, | ||
122 | { VIDIOC_G_FREQUENCY, SAA7146_EXCLUSIVE }, | ||
123 | { VIDIOC_S_FREQUENCY, SAA7146_EXCLUSIVE }, | ||
124 | { VIDIOC_G_AUDIO, SAA7146_EXCLUSIVE }, | ||
125 | { VIDIOC_S_AUDIO, SAA7146_EXCLUSIVE }, | ||
126 | { VIDIOC_DBG_G_REGISTER, SAA7146_EXCLUSIVE }, | ||
127 | { VIDIOC_DBG_S_REGISTER, SAA7146_EXCLUSIVE }, | ||
128 | { MXB_S_AUDIO_CD, SAA7146_EXCLUSIVE }, /* custom control */ | ||
129 | { MXB_S_AUDIO_LINE, SAA7146_EXCLUSIVE }, /* custom control */ | ||
130 | { 0, 0 } | ||
131 | }; | ||
132 | |||
133 | struct mxb | 113 | struct mxb |
134 | { | 114 | { |
135 | struct video_device *video_dev; | 115 | struct video_device *video_dev; |
@@ -424,387 +404,430 @@ void mxb_irq_bh(struct saa7146_dev* dev, u32* irq_mask) | |||
424 | } | 404 | } |
425 | */ | 405 | */ |
426 | 406 | ||
427 | static struct saa7146_ext_vv vv_data; | 407 | static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qc) |
428 | |||
429 | /* this function only gets called when the probing was successful */ | ||
430 | static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) | ||
431 | { | 408 | { |
432 | struct mxb *mxb = (struct mxb *)dev->ext_priv; | 409 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; |
410 | int i; | ||
433 | 411 | ||
434 | DEB_EE(("dev:%p\n", dev)); | 412 | for (i = MAXCONTROLS - 1; i >= 0; i--) { |
413 | if (mxb_controls[i].id == qc->id) { | ||
414 | *qc = mxb_controls[i]; | ||
415 | DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id)); | ||
416 | return 0; | ||
417 | } | ||
418 | } | ||
419 | return dev->ext_vv_data->core_ops->vidioc_queryctrl(file, fh, qc); | ||
420 | } | ||
435 | 421 | ||
436 | /* checking for i2c-devices can be omitted here, because we | 422 | static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *vc) |
437 | already did this in "mxb_vl42_probe" */ | 423 | { |
424 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
425 | struct mxb *mxb = (struct mxb *)dev->ext_priv; | ||
426 | int i; | ||
438 | 427 | ||
439 | saa7146_vv_init(dev, &vv_data); | 428 | for (i = MAXCONTROLS - 1; i >= 0; i--) { |
440 | if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) { | 429 | if (mxb_controls[i].id == vc->id) |
441 | ERR(("cannot register capture v4l2 device. skipping.\n")); | 430 | break; |
442 | return -1; | ||
443 | } | 431 | } |
444 | 432 | ||
445 | /* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/ | 433 | if (i < 0) |
446 | if (MXB_BOARD_CAN_DO_VBI(dev)) { | 434 | return dev->ext_vv_data->core_ops->vidioc_g_ctrl(file, fh, vc); |
447 | if (saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) { | ||
448 | ERR(("cannot register vbi v4l2 device. skipping.\n")); | ||
449 | } | ||
450 | } | ||
451 | 435 | ||
452 | i2c_use_client(mxb->tea6420_1); | 436 | if (vc->id == V4L2_CID_AUDIO_MUTE) { |
453 | i2c_use_client(mxb->tea6420_2); | 437 | vc->value = mxb->cur_mute; |
454 | i2c_use_client(mxb->tea6415c); | 438 | DEB_D(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value)); |
455 | i2c_use_client(mxb->tda9840); | 439 | return 0; |
456 | i2c_use_client(mxb->saa7111a); | 440 | } |
457 | i2c_use_client(mxb->tuner); | ||
458 | |||
459 | printk("mxb: found Multimedia eXtension Board #%d.\n", mxb_num); | ||
460 | 441 | ||
461 | mxb_num++; | 442 | DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value)); |
462 | mxb_init_done(dev); | ||
463 | return 0; | 443 | return 0; |
464 | } | 444 | } |
465 | 445 | ||
466 | static int mxb_detach(struct saa7146_dev *dev) | 446 | static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *vc) |
467 | { | 447 | { |
448 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
468 | struct mxb *mxb = (struct mxb *)dev->ext_priv; | 449 | struct mxb *mxb = (struct mxb *)dev->ext_priv; |
450 | int i = 0; | ||
469 | 451 | ||
470 | DEB_EE(("dev:%p\n", dev)); | 452 | for (i = MAXCONTROLS - 1; i >= 0; i--) { |
471 | 453 | if (mxb_controls[i].id == vc->id) | |
472 | i2c_release_client(mxb->tea6420_1); | 454 | break; |
473 | i2c_release_client(mxb->tea6420_2); | 455 | } |
474 | i2c_release_client(mxb->tea6415c); | ||
475 | i2c_release_client(mxb->tda9840); | ||
476 | i2c_release_client(mxb->saa7111a); | ||
477 | i2c_release_client(mxb->tuner); | ||
478 | |||
479 | saa7146_unregister_device(&mxb->video_dev,dev); | ||
480 | if (MXB_BOARD_CAN_DO_VBI(dev)) | ||
481 | saa7146_unregister_device(&mxb->vbi_dev, dev); | ||
482 | saa7146_vv_release(dev); | ||
483 | 456 | ||
484 | mxb_num--; | 457 | if (i < 0) |
458 | return dev->ext_vv_data->core_ops->vidioc_s_ctrl(file, fh, vc); | ||
485 | 459 | ||
486 | i2c_del_adapter(&mxb->i2c_adapter); | 460 | if (vc->id == V4L2_CID_AUDIO_MUTE) { |
487 | kfree(mxb); | 461 | mxb->cur_mute = vc->value; |
462 | if (!vc->value) { | ||
463 | /* switch the audio-source */ | ||
464 | mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, | ||
465 | &TEA6420_line[video_audio_connect[mxb->cur_input]][0]); | ||
466 | mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, | ||
467 | &TEA6420_line[video_audio_connect[mxb->cur_input]][1]); | ||
468 | } else { | ||
469 | mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, | ||
470 | &TEA6420_line[6][0]); | ||
471 | mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, | ||
472 | &TEA6420_line[6][1]); | ||
473 | } | ||
474 | DEB_EE(("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d.\n", vc->value)); | ||
475 | } | ||
476 | return 0; | ||
477 | } | ||
488 | 478 | ||
479 | static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i) | ||
480 | { | ||
481 | DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index)); | ||
482 | if (i->index < 0 || i->index >= MXB_INPUTS) | ||
483 | return -EINVAL; | ||
484 | memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input)); | ||
489 | return 0; | 485 | return 0; |
490 | } | 486 | } |
491 | 487 | ||
492 | static long mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) | 488 | static int vidioc_g_input(struct file *file, void *fh, unsigned int *i) |
493 | { | 489 | { |
494 | struct saa7146_dev *dev = fh->dev; | 490 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; |
495 | struct mxb *mxb = (struct mxb *)dev->ext_priv; | 491 | struct mxb *mxb = (struct mxb *)dev->ext_priv; |
496 | struct saa7146_vv *vv = dev->vv_data; | 492 | *i = mxb->cur_input; |
497 | 493 | ||
498 | switch(cmd) { | 494 | DEB_EE(("VIDIOC_G_INPUT %d.\n", *i)); |
499 | case VIDIOC_ENUMINPUT: | 495 | return 0; |
500 | { | 496 | } |
501 | struct v4l2_input *i = arg; | ||
502 | 497 | ||
503 | DEB_EE(("VIDIOC_ENUMINPUT %d.\n",i->index)); | 498 | static int vidioc_s_input(struct file *file, void *fh, unsigned int input) |
504 | if (i->index < 0 || i->index >= MXB_INPUTS) | 499 | { |
505 | return -EINVAL; | 500 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; |
506 | memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input)); | 501 | struct mxb *mxb = (struct mxb *)dev->ext_priv; |
507 | return 0; | 502 | struct tea6415c_multiplex vm; |
508 | } | 503 | struct v4l2_routing route; |
509 | /* the saa7146 provides some controls (brightness, contrast, saturation) | 504 | int i = 0; |
510 | which gets registered *after* this function. because of this we have | ||
511 | to return with a value != 0 even if the function succeded.. */ | ||
512 | case VIDIOC_QUERYCTRL: | ||
513 | { | ||
514 | struct v4l2_queryctrl *qc = arg; | ||
515 | int i; | ||
516 | |||
517 | for (i = MAXCONTROLS - 1; i >= 0; i--) { | ||
518 | if (mxb_controls[i].id == qc->id) { | ||
519 | *qc = mxb_controls[i]; | ||
520 | DEB_D(("VIDIOC_QUERYCTRL %d.\n", qc->id)); | ||
521 | return 0; | ||
522 | } | ||
523 | } | ||
524 | return -EAGAIN; | ||
525 | } | ||
526 | case VIDIOC_G_CTRL: | ||
527 | { | ||
528 | struct v4l2_control *vc = arg; | ||
529 | int i; | ||
530 | 505 | ||
531 | for (i = MAXCONTROLS - 1; i >= 0; i--) { | 506 | DEB_EE(("VIDIOC_S_INPUT %d.\n", input)); |
532 | if (mxb_controls[i].id == vc->id) | ||
533 | break; | ||
534 | } | ||
535 | 507 | ||
536 | if (i < 0) | 508 | if (input < 0 || input >= MXB_INPUTS) |
537 | return -EAGAIN; | 509 | return -EINVAL; |
538 | 510 | ||
539 | if (vc->id == V4L2_CID_AUDIO_MUTE) { | 511 | mxb->cur_input = input; |
540 | vc->value = mxb->cur_mute; | ||
541 | DEB_D(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value)); | ||
542 | return 0; | ||
543 | } | ||
544 | 512 | ||
545 | DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n", vc->value)); | 513 | saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source, |
546 | return 0; | 514 | input_port_selection[input].hps_sync); |
547 | } | ||
548 | 515 | ||
549 | case VIDIOC_S_CTRL: | 516 | /* prepare switching of tea6415c and saa7111a; |
550 | { | 517 | have a look at the 'background'-file for further informations */ |
551 | struct v4l2_control *vc = arg; | 518 | switch (input) { |
552 | int i = 0; | 519 | case TUNER: |
520 | i = SAA7115_COMPOSITE0; | ||
521 | vm.in = 3; | ||
522 | vm.out = 17; | ||
553 | 523 | ||
554 | for (i = MAXCONTROLS - 1; i >= 0; i--) { | 524 | if (mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm)) { |
555 | if (mxb_controls[i].id == vc->id) | 525 | printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #1\n"); |
556 | break; | 526 | return -EFAULT; |
557 | } | 527 | } |
528 | /* connect tuner-output always to multicable */ | ||
529 | vm.in = 3; | ||
530 | vm.out = 13; | ||
531 | break; | ||
532 | case AUX3_YC: | ||
533 | /* nothing to be done here. aux3_yc is | ||
534 | directly connected to the saa711a */ | ||
535 | i = SAA7115_SVIDEO1; | ||
536 | break; | ||
537 | case AUX3: | ||
538 | /* nothing to be done here. aux3 is | ||
539 | directly connected to the saa711a */ | ||
540 | i = SAA7115_COMPOSITE1; | ||
541 | break; | ||
542 | case AUX1: | ||
543 | i = SAA7115_COMPOSITE0; | ||
544 | vm.in = 1; | ||
545 | vm.out = 17; | ||
546 | break; | ||
547 | } | ||
558 | 548 | ||
559 | if (i < 0) | 549 | /* switch video in tea6415c only if necessary */ |
560 | return -EAGAIN; | 550 | switch (input) { |
561 | 551 | case TUNER: | |
562 | if (vc->id == V4L2_CID_AUDIO_MUTE) { | 552 | case AUX1: |
563 | mxb->cur_mute = vc->value; | 553 | if (mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm)) { |
564 | if (!vc->value) { | 554 | printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #3\n"); |
565 | /* switch the audio-source */ | 555 | return -EFAULT; |
566 | mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, | ||
567 | &TEA6420_line[video_audio_connect[mxb->cur_input]][0]); | ||
568 | mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, | ||
569 | &TEA6420_line[video_audio_connect[mxb->cur_input]][1]); | ||
570 | } else { | ||
571 | mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, | ||
572 | &TEA6420_line[6][0]); | ||
573 | mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, | ||
574 | &TEA6420_line[6][1]); | ||
575 | } | ||
576 | DEB_EE(("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d.\n", vc->value)); | ||
577 | } | 556 | } |
578 | return 0; | 557 | break; |
558 | default: | ||
559 | break; | ||
579 | } | 560 | } |
580 | case VIDIOC_G_INPUT: | ||
581 | { | ||
582 | int *input = (int *)arg; | ||
583 | *input = mxb->cur_input; | ||
584 | 561 | ||
585 | DEB_EE(("VIDIOC_G_INPUT %d.\n", *input)); | 562 | /* switch video in saa7111a */ |
586 | return 0; | 563 | route.input = i; |
564 | route.output = 0; | ||
565 | if (mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_VIDEO_ROUTING, &route)) | ||
566 | printk(KERN_ERR "VIDIOC_S_INPUT: could not address saa7111a #1.\n"); | ||
567 | |||
568 | /* switch the audio-source only if necessary */ | ||
569 | if (0 == mxb->cur_mute) { | ||
570 | mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, | ||
571 | &TEA6420_line[video_audio_connect[input]][0]); | ||
572 | mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, | ||
573 | &TEA6420_line[video_audio_connect[input]][1]); | ||
587 | } | 574 | } |
588 | case VIDIOC_S_INPUT: | ||
589 | { | ||
590 | int input = *(int *)arg; | ||
591 | struct tea6415c_multiplex vm; | ||
592 | struct v4l2_routing route; | ||
593 | int i = 0; | ||
594 | 575 | ||
595 | DEB_EE(("VIDIOC_S_INPUT %d.\n", input)); | 576 | return 0; |
577 | } | ||
596 | 578 | ||
597 | if (input < 0 || input >= MXB_INPUTS) | 579 | static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t) |
598 | return -EINVAL; | 580 | { |
581 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
582 | struct mxb *mxb = (struct mxb *)dev->ext_priv; | ||
599 | 583 | ||
600 | mxb->cur_input = input; | 584 | if (t->index) { |
585 | DEB_D(("VIDIOC_G_TUNER: channel %d does not have a tuner attached.\n", t->index)); | ||
586 | return -EINVAL; | ||
587 | } | ||
601 | 588 | ||
602 | saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source, | 589 | DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index)); |
603 | input_port_selection[input].hps_sync); | ||
604 | 590 | ||
605 | /* prepare switching of tea6415c and saa7111a; | 591 | memset(t, 0, sizeof(*t)); |
606 | have a look at the 'background'-file for further informations */ | 592 | i2c_clients_command(&mxb->i2c_adapter, VIDIOC_G_TUNER, t); |
607 | switch (input) { | ||
608 | case TUNER: | ||
609 | i = SAA7115_COMPOSITE0; | ||
610 | vm.in = 3; | ||
611 | vm.out = 17; | ||
612 | 593 | ||
613 | if (mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm)) { | 594 | strlcpy(t->name, "TV Tuner", sizeof(t->name)); |
614 | printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #1\n"); | 595 | t->type = V4L2_TUNER_ANALOG_TV; |
615 | return -EFAULT; | 596 | t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | |
616 | } | 597 | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; |
617 | /* connect tuner-output always to multicable */ | 598 | t->audmode = mxb->cur_mode; |
618 | vm.in = 3; | 599 | return 0; |
619 | vm.out = 13; | 600 | } |
620 | break; | ||
621 | case AUX3_YC: | ||
622 | /* nothing to be done here. aux3_yc is | ||
623 | directly connected to the saa711a */ | ||
624 | i = SAA7115_SVIDEO1; | ||
625 | break; | ||
626 | case AUX3: | ||
627 | /* nothing to be done here. aux3 is | ||
628 | directly connected to the saa711a */ | ||
629 | i = SAA7115_COMPOSITE1; | ||
630 | break; | ||
631 | case AUX1: | ||
632 | i = SAA7115_COMPOSITE0; | ||
633 | vm.in = 1; | ||
634 | vm.out = 17; | ||
635 | break; | ||
636 | } | ||
637 | 601 | ||
638 | /* switch video in tea6415c only if necessary */ | 602 | static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t) |
639 | switch (input) { | 603 | { |
640 | case TUNER: | 604 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; |
641 | case AUX1: | 605 | struct mxb *mxb = (struct mxb *)dev->ext_priv; |
642 | if (mxb->tea6415c->driver->command(mxb->tea6415c, TEA6415C_SWITCH, &vm)) { | ||
643 | printk(KERN_ERR "VIDIOC_S_INPUT: could not address tea6415c #3\n"); | ||
644 | return -EFAULT; | ||
645 | } | ||
646 | break; | ||
647 | default: | ||
648 | break; | ||
649 | } | ||
650 | 606 | ||
651 | /* switch video in saa7111a */ | 607 | if (t->index) { |
652 | route.input = i; | 608 | DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n", t->index)); |
653 | route.output = 0; | 609 | return -EINVAL; |
654 | if (mxb->saa7111a->driver->command(mxb->saa7111a, VIDIOC_INT_S_VIDEO_ROUTING, &route)) | 610 | } |
655 | printk("VIDIOC_S_INPUT: could not address saa7111a #1.\n"); | ||
656 | 611 | ||
657 | /* switch the audio-source only if necessary */ | 612 | mxb->cur_mode = t->audmode; |
658 | if( 0 == mxb->cur_mute ) { | 613 | i2c_clients_command(&mxb->i2c_adapter, VIDIOC_S_TUNER, t); |
659 | mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, | 614 | return 0; |
660 | &TEA6420_line[video_audio_connect[input]][0]); | 615 | } |
661 | mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, | ||
662 | &TEA6420_line[video_audio_connect[input]][1]); | ||
663 | } | ||
664 | 616 | ||
665 | return 0; | 617 | static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *f) |
618 | { | ||
619 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
620 | struct mxb *mxb = (struct mxb *)dev->ext_priv; | ||
621 | |||
622 | if (mxb->cur_input) { | ||
623 | DEB_D(("VIDIOC_G_FREQ: channel %d does not have a tuner!\n", | ||
624 | mxb->cur_input)); | ||
625 | return -EINVAL; | ||
666 | } | 626 | } |
667 | case VIDIOC_G_TUNER: | ||
668 | { | ||
669 | struct v4l2_tuner *t = arg; | ||
670 | 627 | ||
671 | if (t->index) { | 628 | *f = mxb->cur_freq; |
672 | DEB_D(("VIDIOC_G_TUNER: channel %d does not have a tuner attached.\n", t->index)); | ||
673 | return -EINVAL; | ||
674 | } | ||
675 | 629 | ||
676 | DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index)); | 630 | DEB_EE(("VIDIOC_G_FREQ: freq:0x%08x.\n", mxb->cur_freq.frequency)); |
631 | return 0; | ||
632 | } | ||
677 | 633 | ||
678 | memset(t, 0, sizeof(*t)); | 634 | static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency *f) |
679 | i2c_clients_command(&mxb->i2c_adapter, cmd, arg); | 635 | { |
636 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
637 | struct mxb *mxb = (struct mxb *)dev->ext_priv; | ||
638 | struct saa7146_vv *vv = dev->vv_data; | ||
680 | 639 | ||
681 | strlcpy(t->name, "TV Tuner", sizeof(t->name)); | 640 | if (f->tuner) |
682 | t->type = V4L2_TUNER_ANALOG_TV; | 641 | return -EINVAL; |
683 | t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | \ | ||
684 | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; | ||
685 | t->audmode = mxb->cur_mode; | ||
686 | return 0; | ||
687 | } | ||
688 | case VIDIOC_S_TUNER: | ||
689 | { | ||
690 | struct v4l2_tuner *t = arg; | ||
691 | 642 | ||
692 | if (t->index) { | 643 | if (V4L2_TUNER_ANALOG_TV != f->type) |
693 | DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n",t->index)); | 644 | return -EINVAL; |
694 | return -EINVAL; | ||
695 | } | ||
696 | 645 | ||
697 | mxb->cur_mode = t->audmode; | 646 | if (mxb->cur_input) { |
698 | i2c_clients_command(&mxb->i2c_adapter, cmd, arg); | 647 | DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n", mxb->cur_input)); |
699 | return 0; | 648 | return -EINVAL; |
700 | } | 649 | } |
701 | case VIDIOC_G_FREQUENCY: | ||
702 | { | ||
703 | struct v4l2_frequency *f = arg; | ||
704 | 650 | ||
705 | if (mxb->cur_input) { | 651 | mxb->cur_freq = *f; |
706 | DEB_D(("VIDIOC_G_FREQ: channel %d does not have a tuner!\n", | 652 | DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency)); |
707 | mxb->cur_input)); | ||
708 | return -EINVAL; | ||
709 | } | ||
710 | 653 | ||
711 | *f = mxb->cur_freq; | 654 | /* tune in desired frequency */ |
655 | mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY, &mxb->cur_freq); | ||
712 | 656 | ||
713 | DEB_EE(("VIDIOC_G_FREQ: freq:0x%08x.\n", mxb->cur_freq.frequency)); | 657 | /* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */ |
714 | return 0; | 658 | spin_lock(&dev->slock); |
659 | vv->vbi_fieldcount = 0; | ||
660 | spin_unlock(&dev->slock); | ||
661 | |||
662 | return 0; | ||
663 | } | ||
664 | |||
665 | static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a) | ||
666 | { | ||
667 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
668 | struct mxb *mxb = (struct mxb *)dev->ext_priv; | ||
669 | |||
670 | if (a->index < 0 || a->index > MXB_INPUTS) { | ||
671 | DEB_D(("VIDIOC_G_AUDIO %d out of range.\n", a->index)); | ||
672 | return -EINVAL; | ||
715 | } | 673 | } |
716 | case VIDIOC_S_FREQUENCY: | ||
717 | { | ||
718 | struct v4l2_frequency *f = arg; | ||
719 | 674 | ||
720 | if (f->tuner) | 675 | DEB_EE(("VIDIOC_G_AUDIO %d.\n", a->index)); |
721 | return -EINVAL; | 676 | memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio)); |
677 | return 0; | ||
678 | } | ||
722 | 679 | ||
723 | if (V4L2_TUNER_ANALOG_TV != f->type) | 680 | static int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a) |
724 | return -EINVAL; | 681 | { |
682 | DEB_D(("VIDIOC_S_AUDIO %d.\n", a->index)); | ||
683 | return 0; | ||
684 | } | ||
725 | 685 | ||
726 | if (mxb->cur_input) { | 686 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
727 | DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n", mxb->cur_input)); | 687 | static int vidioc_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) |
728 | return -EINVAL; | 688 | { |
729 | } | 689 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; |
690 | struct mxb *mxb = (struct mxb *)dev->ext_priv; | ||
730 | 691 | ||
731 | mxb->cur_freq = *f; | 692 | i2c_clients_command(&mxb->i2c_adapter, VIDIOC_DBG_G_REGISTER, reg); |
732 | DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency)); | 693 | return 0; |
694 | } | ||
733 | 695 | ||
734 | /* tune in desired frequency */ | 696 | static int vidioc_s_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) |
735 | mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY, &mxb->cur_freq); | 697 | { |
698 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
699 | struct mxb *mxb = (struct mxb *)dev->ext_priv; | ||
736 | 700 | ||
737 | /* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */ | 701 | i2c_clients_command(&mxb->i2c_adapter, VIDIOC_DBG_S_REGISTER, reg); |
738 | spin_lock(&dev->slock); | 702 | return 0; |
739 | vv->vbi_fieldcount = 0; | 703 | } |
740 | spin_unlock(&dev->slock); | 704 | #endif |
741 | 705 | ||
742 | return 0; | 706 | static long vidioc_default(struct file *file, void *fh, int cmd, void *arg) |
743 | } | 707 | { |
708 | struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; | ||
709 | struct mxb *mxb = (struct mxb *)dev->ext_priv; | ||
710 | |||
711 | switch (cmd) { | ||
744 | case MXB_S_AUDIO_CD: | 712 | case MXB_S_AUDIO_CD: |
745 | { | 713 | { |
746 | int i = *(int*)arg; | 714 | int i = *(int *)arg; |
747 | 715 | ||
748 | if (i < 0 || i >= MXB_AUDIOS) { | 716 | if (i < 0 || i >= MXB_AUDIOS) { |
749 | DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n",i)); | 717 | DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n", i)); |
750 | return -EINVAL; | 718 | return -EINVAL; |
751 | } | 719 | } |
752 | 720 | ||
753 | DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n",i)); | 721 | DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n", i)); |
754 | 722 | ||
755 | mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_cd[i][0]); | 723 | mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, &TEA6420_cd[i][0]); |
756 | mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_cd[i][1]); | 724 | mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, &TEA6420_cd[i][1]); |
757 | 725 | ||
758 | return 0; | 726 | return 0; |
759 | } | 727 | } |
760 | case MXB_S_AUDIO_LINE: | 728 | case MXB_S_AUDIO_LINE: |
761 | { | 729 | { |
762 | int i = *(int*)arg; | 730 | int i = *(int *)arg; |
763 | 731 | ||
764 | if (i < 0 || i >= MXB_AUDIOS) { | 732 | if (i < 0 || i >= MXB_AUDIOS) { |
765 | DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n",i)); | 733 | DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n", i)); |
766 | return -EINVAL; | 734 | return -EINVAL; |
767 | } | 735 | } |
768 | 736 | ||
769 | DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n",i)); | 737 | DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n", i)); |
770 | mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[i][0]); | 738 | mxb->tea6420_1->driver->command(mxb->tea6420_1, TEA6420_SWITCH, &TEA6420_line[i][0]); |
771 | mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[i][1]); | 739 | mxb->tea6420_2->driver->command(mxb->tea6420_2, TEA6420_SWITCH, &TEA6420_line[i][1]); |
772 | 740 | ||
773 | return 0; | 741 | return 0; |
774 | } | 742 | } |
775 | case VIDIOC_G_AUDIO: | 743 | default: |
776 | { | 744 | /* |
777 | struct v4l2_audio *a = arg; | 745 | DEB2(printk("does not handle this ioctl.\n")); |
746 | */ | ||
747 | return -ENOIOCTLCMD; | ||
748 | } | ||
749 | return 0; | ||
750 | } | ||
778 | 751 | ||
779 | if (a->index < 0 || a->index > MXB_INPUTS) { | 752 | static struct saa7146_ext_vv vv_data; |
780 | DEB_D(("VIDIOC_G_AUDIO %d out of range.\n", a->index)); | 753 | |
781 | return -EINVAL; | 754 | /* this function only gets called when the probing was successful */ |
782 | } | 755 | static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) |
756 | { | ||
757 | struct mxb *mxb = (struct mxb *)dev->ext_priv; | ||
783 | 758 | ||
784 | DEB_EE(("VIDIOC_G_AUDIO %d.\n", a->index)); | 759 | DEB_EE(("dev:%p\n", dev)); |
785 | memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio)); | ||
786 | 760 | ||
787 | return 0; | 761 | /* checking for i2c-devices can be omitted here, because we |
788 | } | 762 | already did this in "mxb_vl42_probe" */ |
789 | case VIDIOC_S_AUDIO: | ||
790 | { | ||
791 | struct v4l2_audio *a = arg; | ||
792 | 763 | ||
793 | DEB_D(("VIDIOC_S_AUDIO %d.\n", a->index)); | 764 | saa7146_vv_init(dev, &vv_data); |
794 | return 0; | 765 | vv_data.ops.vidioc_queryctrl = vidioc_queryctrl; |
795 | } | 766 | vv_data.ops.vidioc_g_ctrl = vidioc_g_ctrl; |
767 | vv_data.ops.vidioc_s_ctrl = vidioc_s_ctrl; | ||
768 | vv_data.ops.vidioc_enum_input = vidioc_enum_input; | ||
769 | vv_data.ops.vidioc_g_input = vidioc_g_input; | ||
770 | vv_data.ops.vidioc_s_input = vidioc_s_input; | ||
771 | vv_data.ops.vidioc_g_tuner = vidioc_g_tuner; | ||
772 | vv_data.ops.vidioc_s_tuner = vidioc_s_tuner; | ||
773 | vv_data.ops.vidioc_g_frequency = vidioc_g_frequency; | ||
774 | vv_data.ops.vidioc_s_frequency = vidioc_s_frequency; | ||
775 | vv_data.ops.vidioc_g_audio = vidioc_g_audio; | ||
776 | vv_data.ops.vidioc_s_audio = vidioc_s_audio; | ||
796 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 777 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
797 | case VIDIOC_DBG_S_REGISTER: | 778 | vv_data.ops.vidioc_g_register = vidioc_g_register; |
798 | case VIDIOC_DBG_G_REGISTER: | 779 | vv_data.ops.vidioc_s_register = vidioc_s_register; |
799 | i2c_clients_command(&mxb->i2c_adapter, cmd, arg); | ||
800 | return 0; | ||
801 | #endif | 780 | #endif |
802 | default: | 781 | vv_data.ops.vidioc_default = vidioc_default; |
803 | /* | 782 | if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) { |
804 | DEB2(printk("does not handle this ioctl.\n")); | 783 | ERR(("cannot register capture v4l2 device. skipping.\n")); |
805 | */ | 784 | return -1; |
806 | return -ENOIOCTLCMD; | 785 | } |
786 | |||
787 | /* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/ | ||
788 | if (MXB_BOARD_CAN_DO_VBI(dev)) { | ||
789 | if (saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) { | ||
790 | ERR(("cannot register vbi v4l2 device. skipping.\n")); | ||
791 | } | ||
807 | } | 792 | } |
793 | |||
794 | i2c_use_client(mxb->tea6420_1); | ||
795 | i2c_use_client(mxb->tea6420_2); | ||
796 | i2c_use_client(mxb->tea6415c); | ||
797 | i2c_use_client(mxb->tda9840); | ||
798 | i2c_use_client(mxb->saa7111a); | ||
799 | i2c_use_client(mxb->tuner); | ||
800 | |||
801 | printk("mxb: found Multimedia eXtension Board #%d.\n", mxb_num); | ||
802 | |||
803 | mxb_num++; | ||
804 | mxb_init_done(dev); | ||
805 | return 0; | ||
806 | } | ||
807 | |||
808 | static int mxb_detach(struct saa7146_dev *dev) | ||
809 | { | ||
810 | struct mxb *mxb = (struct mxb *)dev->ext_priv; | ||
811 | |||
812 | DEB_EE(("dev:%p\n", dev)); | ||
813 | |||
814 | i2c_release_client(mxb->tea6420_1); | ||
815 | i2c_release_client(mxb->tea6420_2); | ||
816 | i2c_release_client(mxb->tea6415c); | ||
817 | i2c_release_client(mxb->tda9840); | ||
818 | i2c_release_client(mxb->saa7111a); | ||
819 | i2c_release_client(mxb->tuner); | ||
820 | |||
821 | saa7146_unregister_device(&mxb->video_dev,dev); | ||
822 | if (MXB_BOARD_CAN_DO_VBI(dev)) | ||
823 | saa7146_unregister_device(&mxb->vbi_dev, dev); | ||
824 | saa7146_vv_release(dev); | ||
825 | |||
826 | mxb_num--; | ||
827 | |||
828 | i2c_del_adapter(&mxb->i2c_adapter); | ||
829 | kfree(mxb); | ||
830 | |||
808 | return 0; | 831 | return 0; |
809 | } | 832 | } |
810 | 833 | ||
@@ -885,8 +908,6 @@ static struct saa7146_ext_vv vv_data = { | |||
885 | .stds = &standard[0], | 908 | .stds = &standard[0], |
886 | .num_stds = sizeof(standard)/sizeof(struct saa7146_standard), | 909 | .num_stds = sizeof(standard)/sizeof(struct saa7146_standard), |
887 | .std_callback = &std_callback, | 910 | .std_callback = &std_callback, |
888 | .ioctls = &ioctls[0], | ||
889 | .ioctl = mxb_ioctl, | ||
890 | }; | 911 | }; |
891 | 912 | ||
892 | static struct saa7146_extension extension = { | 913 | static struct saa7146_extension extension = { |
diff --git a/include/media/saa7146_vv.h b/include/media/saa7146_vv.h index c8d0b23fde29..eed5fccc83f3 100644 --- a/include/media/saa7146_vv.h +++ b/include/media/saa7146_vv.h | |||
@@ -150,16 +150,6 @@ struct saa7146_vv | |||
150 | unsigned int resources; /* resource management for device */ | 150 | unsigned int resources; /* resource management for device */ |
151 | }; | 151 | }; |
152 | 152 | ||
153 | #define SAA7146_EXCLUSIVE 0x1 | ||
154 | #define SAA7146_BEFORE 0x2 | ||
155 | #define SAA7146_AFTER 0x4 | ||
156 | |||
157 | struct saa7146_extension_ioctls | ||
158 | { | ||
159 | unsigned int cmd; | ||
160 | int flags; | ||
161 | }; | ||
162 | |||
163 | /* flags */ | 153 | /* flags */ |
164 | #define SAA7146_USE_PORT_B_FOR_VBI 0x2 /* use input port b for vbi hardware bug workaround */ | 154 | #define SAA7146_USE_PORT_B_FOR_VBI 0x2 /* use input port b for vbi hardware bug workaround */ |
165 | 155 | ||
@@ -176,8 +166,10 @@ struct saa7146_ext_vv | |||
176 | int num_stds; | 166 | int num_stds; |
177 | int (*std_callback)(struct saa7146_dev*, struct saa7146_standard *); | 167 | int (*std_callback)(struct saa7146_dev*, struct saa7146_standard *); |
178 | 168 | ||
179 | struct saa7146_extension_ioctls *ioctls; | 169 | /* the extension can override this */ |
180 | long (*ioctl)(struct saa7146_fh *, unsigned int cmd, void *arg); | 170 | struct v4l2_ioctl_ops ops; |
171 | /* pointer to the saa7146 core ops */ | ||
172 | const struct v4l2_ioctl_ops *core_ops; | ||
181 | 173 | ||
182 | struct v4l2_file_operations vbi_fops; | 174 | struct v4l2_file_operations vbi_fops; |
183 | }; | 175 | }; |
@@ -213,6 +205,7 @@ void saa7146_set_hps_source_and_sync(struct saa7146_dev *saa, int source, int sy | |||
213 | void saa7146_set_gpio(struct saa7146_dev *saa, u8 pin, u8 data); | 205 | void saa7146_set_gpio(struct saa7146_dev *saa, u8 pin, u8 data); |
214 | 206 | ||
215 | /* from saa7146_video.c */ | 207 | /* from saa7146_video.c */ |
208 | extern const struct v4l2_ioctl_ops saa7146_video_ioctl_ops; | ||
216 | extern struct saa7146_use_ops saa7146_video_uops; | 209 | extern struct saa7146_use_ops saa7146_video_uops; |
217 | int saa7146_start_preview(struct saa7146_fh *fh); | 210 | int saa7146_start_preview(struct saa7146_fh *fh); |
218 | int saa7146_stop_preview(struct saa7146_fh *fh); | 211 | int saa7146_stop_preview(struct saa7146_fh *fh); |