diff options
author | Hans Verkuil <hverkuil@xs4all.nl> | 2009-01-18 17:59:11 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-03-30 11:42:24 -0400 |
commit | b960074fec573fb1b226d9e2686ce51be807cdf1 (patch) | |
tree | da58b7afa37b0ccd1c06948ad6497cb801553335 /drivers/media/video/mxb.c | |
parent | c9b8b04b267f9a7e472daa06cdf6d4963d503d1f (diff) |
V4L/DVB (10271): saa7146: convert to video_ioctl2.
The conversion to video_ioctl2 is the first phase to converting this driver
to the latest v4l2 framework.
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/mxb.c')
-rw-r--r-- | drivers/media/video/mxb.c | 641 |
1 files changed, 331 insertions, 310 deletions
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 = { |