diff options
author | Hans Verkuil <hans.verkuil@cisco.com> | 2012-05-04 08:16:57 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-05-14 12:44:02 -0400 |
commit | 4967d53dbbcebf590c5ae07c0aea38619ac51954 (patch) | |
tree | 0591424809d99161f6c420d263c6e23cedd8b724 /drivers/media/radio/si470x | |
parent | 528f0f785c042c80294708c5ae2c8005b4a0ee60 (diff) |
[media] si470x: Clean up, introduce the control framework
This cleans up the code and si470x now uses the proper v4l2 frameworks
and passes most of the v4l2-compliance tests.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Tobias Lorenz <tobias.lorenz@gmx.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/radio/si470x')
-rw-r--r-- | drivers/media/radio/si470x/radio-si470x-common.c | 193 | ||||
-rw-r--r-- | drivers/media/radio/si470x/radio-si470x-i2c.c | 65 | ||||
-rw-r--r-- | drivers/media/radio/si470x/radio-si470x-usb.c | 146 | ||||
-rw-r--r-- | drivers/media/radio/si470x/radio-si470x.h | 14 |
4 files changed, 105 insertions, 313 deletions
diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c index 0e740c98786c..de9475f4139e 100644 --- a/drivers/media/radio/si470x/radio-si470x-common.c +++ b/drivers/media/radio/si470x/radio-si470x-common.c | |||
@@ -196,9 +196,9 @@ static int si470x_set_chan(struct si470x_device *radio, unsigned short chan) | |||
196 | } | 196 | } |
197 | 197 | ||
198 | if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) | 198 | if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) |
199 | dev_warn(&radio->videodev->dev, "tune does not complete\n"); | 199 | dev_warn(&radio->videodev.dev, "tune does not complete\n"); |
200 | if (timed_out) | 200 | if (timed_out) |
201 | dev_warn(&radio->videodev->dev, | 201 | dev_warn(&radio->videodev.dev, |
202 | "tune timed out after %u ms\n", tune_timeout); | 202 | "tune timed out after %u ms\n", tune_timeout); |
203 | 203 | ||
204 | stop: | 204 | stop: |
@@ -344,12 +344,12 @@ static int si470x_set_seek(struct si470x_device *radio, | |||
344 | } | 344 | } |
345 | 345 | ||
346 | if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) | 346 | if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) |
347 | dev_warn(&radio->videodev->dev, "seek does not complete\n"); | 347 | dev_warn(&radio->videodev.dev, "seek does not complete\n"); |
348 | if (radio->registers[STATUSRSSI] & STATUSRSSI_SF) | 348 | if (radio->registers[STATUSRSSI] & STATUSRSSI_SF) |
349 | dev_warn(&radio->videodev->dev, | 349 | dev_warn(&radio->videodev.dev, |
350 | "seek failed / band limit reached\n"); | 350 | "seek failed / band limit reached\n"); |
351 | if (timed_out) | 351 | if (timed_out) |
352 | dev_warn(&radio->videodev->dev, | 352 | dev_warn(&radio->videodev.dev, |
353 | "seek timed out after %u ms\n", seek_timeout); | 353 | "seek timed out after %u ms\n", seek_timeout); |
354 | 354 | ||
355 | stop: | 355 | stop: |
@@ -463,7 +463,6 @@ static ssize_t si470x_fops_read(struct file *file, char __user *buf, | |||
463 | unsigned int block_count = 0; | 463 | unsigned int block_count = 0; |
464 | 464 | ||
465 | /* switch on rds reception */ | 465 | /* switch on rds reception */ |
466 | mutex_lock(&radio->lock); | ||
467 | if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) | 466 | if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) |
468 | si470x_rds_on(radio); | 467 | si470x_rds_on(radio); |
469 | 468 | ||
@@ -505,7 +504,6 @@ static ssize_t si470x_fops_read(struct file *file, char __user *buf, | |||
505 | } | 504 | } |
506 | 505 | ||
507 | done: | 506 | done: |
508 | mutex_unlock(&radio->lock); | ||
509 | return retval; | 507 | return retval; |
510 | } | 508 | } |
511 | 509 | ||
@@ -521,10 +519,8 @@ static unsigned int si470x_fops_poll(struct file *file, | |||
521 | 519 | ||
522 | /* switch on rds reception */ | 520 | /* switch on rds reception */ |
523 | 521 | ||
524 | mutex_lock(&radio->lock); | ||
525 | if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) | 522 | if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) |
526 | si470x_rds_on(radio); | 523 | si470x_rds_on(radio); |
527 | mutex_unlock(&radio->lock); | ||
528 | 524 | ||
529 | poll_wait(file, &radio->read_queue, pts); | 525 | poll_wait(file, &radio->read_queue, pts); |
530 | 526 | ||
@@ -553,134 +549,27 @@ static const struct v4l2_file_operations si470x_fops = { | |||
553 | * Video4Linux Interface | 549 | * Video4Linux Interface |
554 | **************************************************************************/ | 550 | **************************************************************************/ |
555 | 551 | ||
556 | /* | ||
557 | * si470x_vidioc_queryctrl - enumerate control items | ||
558 | */ | ||
559 | static int si470x_vidioc_queryctrl(struct file *file, void *priv, | ||
560 | struct v4l2_queryctrl *qc) | ||
561 | { | ||
562 | struct si470x_device *radio = video_drvdata(file); | ||
563 | int retval = -EINVAL; | ||
564 | |||
565 | /* abort if qc->id is below V4L2_CID_BASE */ | ||
566 | if (qc->id < V4L2_CID_BASE) | ||
567 | goto done; | ||
568 | |||
569 | /* search video control */ | ||
570 | switch (qc->id) { | ||
571 | case V4L2_CID_AUDIO_VOLUME: | ||
572 | return v4l2_ctrl_query_fill(qc, 0, 15, 1, 15); | ||
573 | case V4L2_CID_AUDIO_MUTE: | ||
574 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); | ||
575 | } | ||
576 | 552 | ||
577 | /* disable unsupported base controls */ | 553 | static int si470x_s_ctrl(struct v4l2_ctrl *ctrl) |
578 | /* to satisfy kradio and such apps */ | ||
579 | if ((retval == -EINVAL) && (qc->id < V4L2_CID_LASTP1)) { | ||
580 | qc->flags = V4L2_CTRL_FLAG_DISABLED; | ||
581 | retval = 0; | ||
582 | } | ||
583 | |||
584 | done: | ||
585 | if (retval < 0) | ||
586 | dev_warn(&radio->videodev->dev, | ||
587 | "query controls failed with %d\n", retval); | ||
588 | return retval; | ||
589 | } | ||
590 | |||
591 | |||
592 | /* | ||
593 | * si470x_vidioc_g_ctrl - get the value of a control | ||
594 | */ | ||
595 | static int si470x_vidioc_g_ctrl(struct file *file, void *priv, | ||
596 | struct v4l2_control *ctrl) | ||
597 | { | 554 | { |
598 | struct si470x_device *radio = video_drvdata(file); | 555 | struct si470x_device *radio = |
599 | int retval = 0; | 556 | container_of(ctrl->handler, struct si470x_device, hdl); |
600 | |||
601 | mutex_lock(&radio->lock); | ||
602 | /* safety checks */ | ||
603 | retval = si470x_disconnect_check(radio); | ||
604 | if (retval) | ||
605 | goto done; | ||
606 | |||
607 | switch (ctrl->id) { | ||
608 | case V4L2_CID_AUDIO_VOLUME: | ||
609 | ctrl->value = radio->registers[SYSCONFIG2] & | ||
610 | SYSCONFIG2_VOLUME; | ||
611 | break; | ||
612 | case V4L2_CID_AUDIO_MUTE: | ||
613 | ctrl->value = ((radio->registers[POWERCFG] & | ||
614 | POWERCFG_DMUTE) == 0) ? 1 : 0; | ||
615 | break; | ||
616 | default: | ||
617 | retval = -EINVAL; | ||
618 | } | ||
619 | |||
620 | done: | ||
621 | if (retval < 0) | ||
622 | dev_warn(&radio->videodev->dev, | ||
623 | "get control failed with %d\n", retval); | ||
624 | |||
625 | mutex_unlock(&radio->lock); | ||
626 | return retval; | ||
627 | } | ||
628 | |||
629 | |||
630 | /* | ||
631 | * si470x_vidioc_s_ctrl - set the value of a control | ||
632 | */ | ||
633 | static int si470x_vidioc_s_ctrl(struct file *file, void *priv, | ||
634 | struct v4l2_control *ctrl) | ||
635 | { | ||
636 | struct si470x_device *radio = video_drvdata(file); | ||
637 | int retval = 0; | ||
638 | |||
639 | mutex_lock(&radio->lock); | ||
640 | /* safety checks */ | ||
641 | retval = si470x_disconnect_check(radio); | ||
642 | if (retval) | ||
643 | goto done; | ||
644 | 557 | ||
645 | switch (ctrl->id) { | 558 | switch (ctrl->id) { |
646 | case V4L2_CID_AUDIO_VOLUME: | 559 | case V4L2_CID_AUDIO_VOLUME: |
647 | radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_VOLUME; | 560 | radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_VOLUME; |
648 | radio->registers[SYSCONFIG2] |= ctrl->value; | 561 | radio->registers[SYSCONFIG2] |= ctrl->val; |
649 | retval = si470x_set_register(radio, SYSCONFIG2); | 562 | return si470x_set_register(radio, SYSCONFIG2); |
650 | break; | ||
651 | case V4L2_CID_AUDIO_MUTE: | 563 | case V4L2_CID_AUDIO_MUTE: |
652 | if (ctrl->value == 1) | 564 | if (ctrl->val) |
653 | radio->registers[POWERCFG] &= ~POWERCFG_DMUTE; | 565 | radio->registers[POWERCFG] &= ~POWERCFG_DMUTE; |
654 | else | 566 | else |
655 | radio->registers[POWERCFG] |= POWERCFG_DMUTE; | 567 | radio->registers[POWERCFG] |= POWERCFG_DMUTE; |
656 | retval = si470x_set_register(radio, POWERCFG); | 568 | return si470x_set_register(radio, POWERCFG); |
657 | break; | 569 | break; |
658 | default: | 570 | default: |
659 | retval = -EINVAL; | 571 | return -EINVAL; |
660 | } | 572 | } |
661 | |||
662 | done: | ||
663 | if (retval < 0) | ||
664 | dev_warn(&radio->videodev->dev, | ||
665 | "set control failed with %d\n", retval); | ||
666 | mutex_unlock(&radio->lock); | ||
667 | return retval; | ||
668 | } | ||
669 | |||
670 | |||
671 | /* | ||
672 | * si470x_vidioc_g_audio - get audio attributes | ||
673 | */ | ||
674 | static int si470x_vidioc_g_audio(struct file *file, void *priv, | ||
675 | struct v4l2_audio *audio) | ||
676 | { | ||
677 | /* driver constants */ | ||
678 | audio->index = 0; | ||
679 | strcpy(audio->name, "Radio"); | ||
680 | audio->capability = V4L2_AUDCAP_STEREO; | ||
681 | audio->mode = 0; | ||
682 | |||
683 | return 0; | ||
684 | } | 573 | } |
685 | 574 | ||
686 | 575 | ||
@@ -693,12 +582,6 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv, | |||
693 | struct si470x_device *radio = video_drvdata(file); | 582 | struct si470x_device *radio = video_drvdata(file); |
694 | int retval = 0; | 583 | int retval = 0; |
695 | 584 | ||
696 | mutex_lock(&radio->lock); | ||
697 | /* safety checks */ | ||
698 | retval = si470x_disconnect_check(radio); | ||
699 | if (retval) | ||
700 | goto done; | ||
701 | |||
702 | if (tuner->index != 0) { | 585 | if (tuner->index != 0) { |
703 | retval = -EINVAL; | 586 | retval = -EINVAL; |
704 | goto done; | 587 | goto done; |
@@ -737,7 +620,7 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv, | |||
737 | if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 0) | 620 | if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 0) |
738 | tuner->rxsubchans = V4L2_TUNER_SUB_MONO; | 621 | tuner->rxsubchans = V4L2_TUNER_SUB_MONO; |
739 | else | 622 | else |
740 | tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; | 623 | tuner->rxsubchans = V4L2_TUNER_SUB_STEREO; |
741 | /* If there is a reliable method of detecting an RDS channel, | 624 | /* If there is a reliable method of detecting an RDS channel, |
742 | then this code should check for that before setting this | 625 | then this code should check for that before setting this |
743 | RDS subchannel. */ | 626 | RDS subchannel. */ |
@@ -761,9 +644,8 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv, | |||
761 | 644 | ||
762 | done: | 645 | done: |
763 | if (retval < 0) | 646 | if (retval < 0) |
764 | dev_warn(&radio->videodev->dev, | 647 | dev_warn(&radio->videodev.dev, |
765 | "get tuner failed with %d\n", retval); | 648 | "get tuner failed with %d\n", retval); |
766 | mutex_unlock(&radio->lock); | ||
767 | return retval; | 649 | return retval; |
768 | } | 650 | } |
769 | 651 | ||
@@ -777,12 +659,6 @@ static int si470x_vidioc_s_tuner(struct file *file, void *priv, | |||
777 | struct si470x_device *radio = video_drvdata(file); | 659 | struct si470x_device *radio = video_drvdata(file); |
778 | int retval = 0; | 660 | int retval = 0; |
779 | 661 | ||
780 | mutex_lock(&radio->lock); | ||
781 | /* safety checks */ | ||
782 | retval = si470x_disconnect_check(radio); | ||
783 | if (retval) | ||
784 | goto done; | ||
785 | |||
786 | if (tuner->index != 0) | 662 | if (tuner->index != 0) |
787 | goto done; | 663 | goto done; |
788 | 664 | ||
@@ -802,9 +678,8 @@ static int si470x_vidioc_s_tuner(struct file *file, void *priv, | |||
802 | 678 | ||
803 | done: | 679 | done: |
804 | if (retval < 0) | 680 | if (retval < 0) |
805 | dev_warn(&radio->videodev->dev, | 681 | dev_warn(&radio->videodev.dev, |
806 | "set tuner failed with %d\n", retval); | 682 | "set tuner failed with %d\n", retval); |
807 | mutex_unlock(&radio->lock); | ||
808 | return retval; | 683 | return retval; |
809 | } | 684 | } |
810 | 685 | ||
@@ -818,12 +693,6 @@ static int si470x_vidioc_g_frequency(struct file *file, void *priv, | |||
818 | struct si470x_device *radio = video_drvdata(file); | 693 | struct si470x_device *radio = video_drvdata(file); |
819 | int retval = 0; | 694 | int retval = 0; |
820 | 695 | ||
821 | /* safety checks */ | ||
822 | mutex_lock(&radio->lock); | ||
823 | retval = si470x_disconnect_check(radio); | ||
824 | if (retval) | ||
825 | goto done; | ||
826 | |||
827 | if (freq->tuner != 0) { | 696 | if (freq->tuner != 0) { |
828 | retval = -EINVAL; | 697 | retval = -EINVAL; |
829 | goto done; | 698 | goto done; |
@@ -834,9 +703,8 @@ static int si470x_vidioc_g_frequency(struct file *file, void *priv, | |||
834 | 703 | ||
835 | done: | 704 | done: |
836 | if (retval < 0) | 705 | if (retval < 0) |
837 | dev_warn(&radio->videodev->dev, | 706 | dev_warn(&radio->videodev.dev, |
838 | "get frequency failed with %d\n", retval); | 707 | "get frequency failed with %d\n", retval); |
839 | mutex_unlock(&radio->lock); | ||
840 | return retval; | 708 | return retval; |
841 | } | 709 | } |
842 | 710 | ||
@@ -850,12 +718,6 @@ static int si470x_vidioc_s_frequency(struct file *file, void *priv, | |||
850 | struct si470x_device *radio = video_drvdata(file); | 718 | struct si470x_device *radio = video_drvdata(file); |
851 | int retval = 0; | 719 | int retval = 0; |
852 | 720 | ||
853 | mutex_lock(&radio->lock); | ||
854 | /* safety checks */ | ||
855 | retval = si470x_disconnect_check(radio); | ||
856 | if (retval) | ||
857 | goto done; | ||
858 | |||
859 | if (freq->tuner != 0) { | 721 | if (freq->tuner != 0) { |
860 | retval = -EINVAL; | 722 | retval = -EINVAL; |
861 | goto done; | 723 | goto done; |
@@ -865,9 +727,8 @@ static int si470x_vidioc_s_frequency(struct file *file, void *priv, | |||
865 | 727 | ||
866 | done: | 728 | done: |
867 | if (retval < 0) | 729 | if (retval < 0) |
868 | dev_warn(&radio->videodev->dev, | 730 | dev_warn(&radio->videodev.dev, |
869 | "set frequency failed with %d\n", retval); | 731 | "set frequency failed with %d\n", retval); |
870 | mutex_unlock(&radio->lock); | ||
871 | return retval; | 732 | return retval; |
872 | } | 733 | } |
873 | 734 | ||
@@ -881,12 +742,6 @@ static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv, | |||
881 | struct si470x_device *radio = video_drvdata(file); | 742 | struct si470x_device *radio = video_drvdata(file); |
882 | int retval = 0; | 743 | int retval = 0; |
883 | 744 | ||
884 | mutex_lock(&radio->lock); | ||
885 | /* safety checks */ | ||
886 | retval = si470x_disconnect_check(radio); | ||
887 | if (retval) | ||
888 | goto done; | ||
889 | |||
890 | if (seek->tuner != 0) { | 745 | if (seek->tuner != 0) { |
891 | retval = -EINVAL; | 746 | retval = -EINVAL; |
892 | goto done; | 747 | goto done; |
@@ -896,22 +751,20 @@ static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv, | |||
896 | 751 | ||
897 | done: | 752 | done: |
898 | if (retval < 0) | 753 | if (retval < 0) |
899 | dev_warn(&radio->videodev->dev, | 754 | dev_warn(&radio->videodev.dev, |
900 | "set hardware frequency seek failed with %d\n", retval); | 755 | "set hardware frequency seek failed with %d\n", retval); |
901 | mutex_unlock(&radio->lock); | ||
902 | return retval; | 756 | return retval; |
903 | } | 757 | } |
904 | 758 | ||
759 | const struct v4l2_ctrl_ops si470x_ctrl_ops = { | ||
760 | .s_ctrl = si470x_s_ctrl, | ||
761 | }; | ||
905 | 762 | ||
906 | /* | 763 | /* |
907 | * si470x_ioctl_ops - video device ioctl operations | 764 | * si470x_ioctl_ops - video device ioctl operations |
908 | */ | 765 | */ |
909 | static const struct v4l2_ioctl_ops si470x_ioctl_ops = { | 766 | static const struct v4l2_ioctl_ops si470x_ioctl_ops = { |
910 | .vidioc_querycap = si470x_vidioc_querycap, | 767 | .vidioc_querycap = si470x_vidioc_querycap, |
911 | .vidioc_queryctrl = si470x_vidioc_queryctrl, | ||
912 | .vidioc_g_ctrl = si470x_vidioc_g_ctrl, | ||
913 | .vidioc_s_ctrl = si470x_vidioc_s_ctrl, | ||
914 | .vidioc_g_audio = si470x_vidioc_g_audio, | ||
915 | .vidioc_g_tuner = si470x_vidioc_g_tuner, | 768 | .vidioc_g_tuner = si470x_vidioc_g_tuner, |
916 | .vidioc_s_tuner = si470x_vidioc_s_tuner, | 769 | .vidioc_s_tuner = si470x_vidioc_s_tuner, |
917 | .vidioc_g_frequency = si470x_vidioc_g_frequency, | 770 | .vidioc_g_frequency = si470x_vidioc_g_frequency, |
@@ -926,6 +779,6 @@ static const struct v4l2_ioctl_ops si470x_ioctl_ops = { | |||
926 | struct video_device si470x_viddev_template = { | 779 | struct video_device si470x_viddev_template = { |
927 | .fops = &si470x_fops, | 780 | .fops = &si470x_fops, |
928 | .name = DRIVER_NAME, | 781 | .name = DRIVER_NAME, |
929 | .release = video_device_release, | 782 | .release = video_device_release_empty, |
930 | .ioctl_ops = &si470x_ioctl_ops, | 783 | .ioctl_ops = &si470x_ioctl_ops, |
931 | }; | 784 | }; |
diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index 9b546a5523f3..a80044c5874e 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c | |||
@@ -162,20 +162,6 @@ static int si470x_get_all_registers(struct si470x_device *radio) | |||
162 | 162 | ||
163 | 163 | ||
164 | /************************************************************************** | 164 | /************************************************************************** |
165 | * General Driver Functions - DISCONNECT_CHECK | ||
166 | **************************************************************************/ | ||
167 | |||
168 | /* | ||
169 | * si470x_disconnect_check - check whether radio disconnects | ||
170 | */ | ||
171 | int si470x_disconnect_check(struct si470x_device *radio) | ||
172 | { | ||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | |||
177 | |||
178 | /************************************************************************** | ||
179 | * File Operations Interface | 165 | * File Operations Interface |
180 | **************************************************************************/ | 166 | **************************************************************************/ |
181 | 167 | ||
@@ -185,12 +171,12 @@ int si470x_disconnect_check(struct si470x_device *radio) | |||
185 | int si470x_fops_open(struct file *file) | 171 | int si470x_fops_open(struct file *file) |
186 | { | 172 | { |
187 | struct si470x_device *radio = video_drvdata(file); | 173 | struct si470x_device *radio = video_drvdata(file); |
188 | int retval = 0; | 174 | int retval = v4l2_fh_open(file); |
189 | 175 | ||
190 | mutex_lock(&radio->lock); | 176 | if (retval) |
191 | radio->users++; | 177 | return retval; |
192 | 178 | ||
193 | if (radio->users == 1) { | 179 | if (v4l2_fh_is_singular_file(file)) { |
194 | /* start radio */ | 180 | /* start radio */ |
195 | retval = si470x_start(radio); | 181 | retval = si470x_start(radio); |
196 | if (retval < 0) | 182 | if (retval < 0) |
@@ -205,7 +191,8 @@ int si470x_fops_open(struct file *file) | |||
205 | } | 191 | } |
206 | 192 | ||
207 | done: | 193 | done: |
208 | mutex_unlock(&radio->lock); | 194 | if (retval) |
195 | v4l2_fh_release(file); | ||
209 | return retval; | 196 | return retval; |
210 | } | 197 | } |
211 | 198 | ||
@@ -216,21 +203,12 @@ done: | |||
216 | int si470x_fops_release(struct file *file) | 203 | int si470x_fops_release(struct file *file) |
217 | { | 204 | { |
218 | struct si470x_device *radio = video_drvdata(file); | 205 | struct si470x_device *radio = video_drvdata(file); |
219 | int retval = 0; | ||
220 | |||
221 | /* safety check */ | ||
222 | if (!radio) | ||
223 | return -ENODEV; | ||
224 | 206 | ||
225 | mutex_lock(&radio->lock); | 207 | if (v4l2_fh_is_singular_file(file)) |
226 | radio->users--; | ||
227 | if (radio->users == 0) | ||
228 | /* stop radio */ | 208 | /* stop radio */ |
229 | retval = si470x_stop(radio); | 209 | si470x_stop(radio); |
230 | 210 | ||
231 | mutex_unlock(&radio->lock); | 211 | return v4l2_fh_release(file); |
232 | |||
233 | return retval; | ||
234 | } | 212 | } |
235 | 213 | ||
236 | 214 | ||
@@ -371,32 +349,25 @@ static int __devinit si470x_i2c_probe(struct i2c_client *client, | |||
371 | goto err_initial; | 349 | goto err_initial; |
372 | } | 350 | } |
373 | 351 | ||
374 | radio->users = 0; | ||
375 | radio->client = client; | 352 | radio->client = client; |
376 | mutex_init(&radio->lock); | 353 | mutex_init(&radio->lock); |
377 | 354 | ||
378 | /* video device allocation and initialization */ | 355 | /* video device initialization */ |
379 | radio->videodev = video_device_alloc(); | 356 | radio->videodev = si470x_viddev_template; |
380 | if (!radio->videodev) { | 357 | video_set_drvdata(&radio->videodev, radio); |
381 | retval = -ENOMEM; | ||
382 | goto err_radio; | ||
383 | } | ||
384 | memcpy(radio->videodev, &si470x_viddev_template, | ||
385 | sizeof(si470x_viddev_template)); | ||
386 | video_set_drvdata(radio->videodev, radio); | ||
387 | 358 | ||
388 | /* power up : need 110ms */ | 359 | /* power up : need 110ms */ |
389 | radio->registers[POWERCFG] = POWERCFG_ENABLE; | 360 | radio->registers[POWERCFG] = POWERCFG_ENABLE; |
390 | if (si470x_set_register(radio, POWERCFG) < 0) { | 361 | if (si470x_set_register(radio, POWERCFG) < 0) { |
391 | retval = -EIO; | 362 | retval = -EIO; |
392 | goto err_video; | 363 | goto err_radio; |
393 | } | 364 | } |
394 | msleep(110); | 365 | msleep(110); |
395 | 366 | ||
396 | /* get device and chip versions */ | 367 | /* get device and chip versions */ |
397 | if (si470x_get_all_registers(radio) < 0) { | 368 | if (si470x_get_all_registers(radio) < 0) { |
398 | retval = -EIO; | 369 | retval = -EIO; |
399 | goto err_video; | 370 | goto err_radio; |
400 | } | 371 | } |
401 | dev_info(&client->dev, "DeviceID=0x%4.4hx ChipID=0x%4.4hx\n", | 372 | dev_info(&client->dev, "DeviceID=0x%4.4hx ChipID=0x%4.4hx\n", |
402 | radio->registers[DEVICEID], radio->registers[CHIPID]); | 373 | radio->registers[DEVICEID], radio->registers[CHIPID]); |
@@ -427,7 +398,7 @@ static int __devinit si470x_i2c_probe(struct i2c_client *client, | |||
427 | radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL); | 398 | radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL); |
428 | if (!radio->buffer) { | 399 | if (!radio->buffer) { |
429 | retval = -EIO; | 400 | retval = -EIO; |
430 | goto err_video; | 401 | goto err_radio; |
431 | } | 402 | } |
432 | 403 | ||
433 | /* rds buffer configuration */ | 404 | /* rds buffer configuration */ |
@@ -447,7 +418,7 @@ static int __devinit si470x_i2c_probe(struct i2c_client *client, | |||
447 | } | 418 | } |
448 | 419 | ||
449 | /* register video device */ | 420 | /* register video device */ |
450 | retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, | 421 | retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, |
451 | radio_nr); | 422 | radio_nr); |
452 | if (retval) { | 423 | if (retval) { |
453 | dev_warn(&client->dev, "Could not register video device\n"); | 424 | dev_warn(&client->dev, "Could not register video device\n"); |
@@ -460,8 +431,6 @@ err_all: | |||
460 | free_irq(client->irq, radio); | 431 | free_irq(client->irq, radio); |
461 | err_rds: | 432 | err_rds: |
462 | kfree(radio->buffer); | 433 | kfree(radio->buffer); |
463 | err_video: | ||
464 | video_device_release(radio->videodev); | ||
465 | err_radio: | 434 | err_radio: |
466 | kfree(radio); | 435 | kfree(radio); |
467 | err_initial: | 436 | err_initial: |
@@ -477,7 +446,7 @@ static __devexit int si470x_i2c_remove(struct i2c_client *client) | |||
477 | struct si470x_device *radio = i2c_get_clientdata(client); | 446 | struct si470x_device *radio = i2c_get_clientdata(client); |
478 | 447 | ||
479 | free_irq(client->irq, radio); | 448 | free_irq(client->irq, radio); |
480 | video_unregister_device(radio->videodev); | 449 | video_unregister_device(&radio->videodev); |
481 | kfree(radio); | 450 | kfree(radio); |
482 | 451 | ||
483 | return 0; | 452 | return 0; |
diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c index b7debb67932a..f133c3dea648 100644 --- a/drivers/media/radio/si470x/radio-si470x-usb.c +++ b/drivers/media/radio/si470x/radio-si470x-usb.c | |||
@@ -367,23 +367,6 @@ static int si470x_get_scratch_page_versions(struct si470x_device *radio) | |||
367 | 367 | ||
368 | 368 | ||
369 | /************************************************************************** | 369 | /************************************************************************** |
370 | * General Driver Functions - DISCONNECT_CHECK | ||
371 | **************************************************************************/ | ||
372 | |||
373 | /* | ||
374 | * si470x_disconnect_check - check whether radio disconnects | ||
375 | */ | ||
376 | int si470x_disconnect_check(struct si470x_device *radio) | ||
377 | { | ||
378 | if (radio->disconnected) | ||
379 | return -EIO; | ||
380 | else | ||
381 | return 0; | ||
382 | } | ||
383 | |||
384 | |||
385 | |||
386 | /************************************************************************** | ||
387 | * RDS Driver Functions | 370 | * RDS Driver Functions |
388 | **************************************************************************/ | 371 | **************************************************************************/ |
389 | 372 | ||
@@ -414,9 +397,6 @@ static void si470x_int_in_callback(struct urb *urb) | |||
414 | } | 397 | } |
415 | } | 398 | } |
416 | 399 | ||
417 | /* safety checks */ | ||
418 | if (radio->disconnected) | ||
419 | return; | ||
420 | if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) | 400 | if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) |
421 | goto resubmit; | 401 | goto resubmit; |
422 | 402 | ||
@@ -512,19 +492,16 @@ resubmit: | |||
512 | int si470x_fops_open(struct file *file) | 492 | int si470x_fops_open(struct file *file) |
513 | { | 493 | { |
514 | struct si470x_device *radio = video_drvdata(file); | 494 | struct si470x_device *radio = video_drvdata(file); |
515 | int retval; | 495 | int retval = v4l2_fh_open(file); |
516 | 496 | ||
517 | mutex_lock(&radio->lock); | 497 | if (retval) |
518 | radio->users++; | 498 | return retval; |
519 | 499 | ||
520 | retval = usb_autopm_get_interface(radio->intf); | 500 | retval = usb_autopm_get_interface(radio->intf); |
521 | if (retval < 0) { | 501 | if (retval < 0) |
522 | radio->users--; | ||
523 | retval = -EIO; | ||
524 | goto done; | 502 | goto done; |
525 | } | ||
526 | 503 | ||
527 | if (radio->users == 1) { | 504 | if (v4l2_fh_is_singular_file(file)) { |
528 | /* start radio */ | 505 | /* start radio */ |
529 | retval = si470x_start(radio); | 506 | retval = si470x_start(radio); |
530 | if (retval < 0) { | 507 | if (retval < 0) { |
@@ -555,7 +532,8 @@ int si470x_fops_open(struct file *file) | |||
555 | } | 532 | } |
556 | 533 | ||
557 | done: | 534 | done: |
558 | mutex_unlock(&radio->lock); | 535 | if (retval) |
536 | v4l2_fh_release(file); | ||
559 | return retval; | 537 | return retval; |
560 | } | 538 | } |
561 | 539 | ||
@@ -566,45 +544,36 @@ done: | |||
566 | int si470x_fops_release(struct file *file) | 544 | int si470x_fops_release(struct file *file) |
567 | { | 545 | { |
568 | struct si470x_device *radio = video_drvdata(file); | 546 | struct si470x_device *radio = video_drvdata(file); |
569 | int retval = 0; | ||
570 | 547 | ||
571 | /* safety check */ | 548 | if (v4l2_fh_is_singular_file(file)) { |
572 | if (!radio) { | ||
573 | retval = -ENODEV; | ||
574 | goto done; | ||
575 | } | ||
576 | |||
577 | mutex_lock(&radio->lock); | ||
578 | radio->users--; | ||
579 | if (radio->users == 0) { | ||
580 | /* shutdown interrupt handler */ | 549 | /* shutdown interrupt handler */ |
581 | if (radio->int_in_running) { | 550 | if (radio->int_in_running) { |
582 | radio->int_in_running = 0; | 551 | radio->int_in_running = 0; |
583 | if (radio->int_in_urb) | 552 | if (radio->int_in_urb) |
584 | usb_kill_urb(radio->int_in_urb); | 553 | usb_kill_urb(radio->int_in_urb); |
585 | } | ||
586 | |||
587 | if (radio->disconnected) { | ||
588 | video_unregister_device(radio->videodev); | ||
589 | kfree(radio->int_in_buffer); | ||
590 | kfree(radio->buffer); | ||
591 | mutex_unlock(&radio->lock); | ||
592 | kfree(radio); | ||
593 | goto done; | ||
594 | } | 554 | } |
595 | 555 | ||
596 | /* cancel read processes */ | 556 | /* cancel read processes */ |
597 | wake_up_interruptible(&radio->read_queue); | 557 | wake_up_interruptible(&radio->read_queue); |
598 | 558 | ||
599 | /* stop radio */ | 559 | /* stop radio */ |
600 | retval = si470x_stop(radio); | 560 | si470x_stop(radio); |
601 | usb_autopm_put_interface(radio->intf); | 561 | usb_autopm_put_interface(radio->intf); |
602 | } | 562 | } |
603 | mutex_unlock(&radio->lock); | 563 | return v4l2_fh_release(file); |
604 | done: | ||
605 | return retval; | ||
606 | } | 564 | } |
607 | 565 | ||
566 | static void si470x_usb_release(struct video_device *vdev) | ||
567 | { | ||
568 | struct si470x_device *radio = video_get_drvdata(vdev); | ||
569 | |||
570 | usb_free_urb(radio->int_in_urb); | ||
571 | v4l2_ctrl_handler_free(&radio->hdl); | ||
572 | v4l2_device_unregister(&radio->v4l2_dev); | ||
573 | kfree(radio->int_in_buffer); | ||
574 | kfree(radio->buffer); | ||
575 | kfree(radio); | ||
576 | } | ||
608 | 577 | ||
609 | 578 | ||
610 | /************************************************************************** | 579 | /************************************************************************** |
@@ -623,9 +592,9 @@ int si470x_vidioc_querycap(struct file *file, void *priv, | |||
623 | strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card)); | 592 | strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card)); |
624 | usb_make_path(radio->usbdev, capability->bus_info, | 593 | usb_make_path(radio->usbdev, capability->bus_info, |
625 | sizeof(capability->bus_info)); | 594 | sizeof(capability->bus_info)); |
626 | capability->capabilities = V4L2_CAP_HW_FREQ_SEEK | | 595 | capability->device_caps = V4L2_CAP_HW_FREQ_SEEK | |
627 | V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE; | 596 | V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE; |
628 | 597 | capability->capabilities = capability->device_caps | V4L2_CAP_DEVICE_CAPS; | |
629 | return 0; | 598 | return 0; |
630 | } | 599 | } |
631 | 600 | ||
@@ -653,8 +622,6 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, | |||
653 | retval = -ENOMEM; | 622 | retval = -ENOMEM; |
654 | goto err_initial; | 623 | goto err_initial; |
655 | } | 624 | } |
656 | radio->users = 0; | ||
657 | radio->disconnected = 0; | ||
658 | radio->usbdev = interface_to_usbdev(intf); | 625 | radio->usbdev = interface_to_usbdev(intf); |
659 | radio->intf = intf; | 626 | radio->intf = intf; |
660 | mutex_init(&radio->lock); | 627 | mutex_init(&radio->lock); |
@@ -691,20 +658,34 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, | |||
691 | goto err_intbuffer; | 658 | goto err_intbuffer; |
692 | } | 659 | } |
693 | 660 | ||
694 | /* video device allocation and initialization */ | 661 | retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev); |
695 | radio->videodev = video_device_alloc(); | 662 | if (retval < 0) { |
696 | if (!radio->videodev) { | 663 | dev_err(&intf->dev, "couldn't register v4l2_device\n"); |
697 | retval = -ENOMEM; | ||
698 | goto err_urb; | 664 | goto err_urb; |
699 | } | 665 | } |
700 | memcpy(radio->videodev, &si470x_viddev_template, | 666 | |
701 | sizeof(si470x_viddev_template)); | 667 | v4l2_ctrl_handler_init(&radio->hdl, 2); |
702 | video_set_drvdata(radio->videodev, radio); | 668 | v4l2_ctrl_new_std(&radio->hdl, &si470x_ctrl_ops, |
669 | V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1); | ||
670 | v4l2_ctrl_new_std(&radio->hdl, &si470x_ctrl_ops, | ||
671 | V4L2_CID_AUDIO_VOLUME, 0, 15, 1, 15); | ||
672 | if (radio->hdl.error) { | ||
673 | retval = radio->hdl.error; | ||
674 | dev_err(&intf->dev, "couldn't register control\n"); | ||
675 | goto err_dev; | ||
676 | } | ||
677 | radio->videodev = si470x_viddev_template; | ||
678 | radio->videodev.ctrl_handler = &radio->hdl; | ||
679 | radio->videodev.lock = &radio->lock; | ||
680 | radio->videodev.v4l2_dev = &radio->v4l2_dev; | ||
681 | radio->videodev.release = si470x_usb_release; | ||
682 | set_bit(V4L2_FL_USE_FH_PRIO, &radio->videodev.flags); | ||
683 | video_set_drvdata(&radio->videodev, radio); | ||
703 | 684 | ||
704 | /* get device and chip versions */ | 685 | /* get device and chip versions */ |
705 | if (si470x_get_all_registers(radio) < 0) { | 686 | if (si470x_get_all_registers(radio) < 0) { |
706 | retval = -EIO; | 687 | retval = -EIO; |
707 | goto err_video; | 688 | goto err_ctrl; |
708 | } | 689 | } |
709 | dev_info(&intf->dev, "DeviceID=0x%4.4hx ChipID=0x%4.4hx\n", | 690 | dev_info(&intf->dev, "DeviceID=0x%4.4hx ChipID=0x%4.4hx\n", |
710 | radio->registers[DEVICEID], radio->registers[CHIPID]); | 691 | radio->registers[DEVICEID], radio->registers[CHIPID]); |
@@ -721,7 +702,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, | |||
721 | /* get software and hardware versions */ | 702 | /* get software and hardware versions */ |
722 | if (si470x_get_scratch_page_versions(radio) < 0) { | 703 | if (si470x_get_scratch_page_versions(radio) < 0) { |
723 | retval = -EIO; | 704 | retval = -EIO; |
724 | goto err_video; | 705 | goto err_ctrl; |
725 | } | 706 | } |
726 | dev_info(&intf->dev, "software version %d, hardware version %d\n", | 707 | dev_info(&intf->dev, "software version %d, hardware version %d\n", |
727 | radio->software_version, radio->hardware_version); | 708 | radio->software_version, radio->hardware_version); |
@@ -764,28 +745,30 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, | |||
764 | radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL); | 745 | radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL); |
765 | if (!radio->buffer) { | 746 | if (!radio->buffer) { |
766 | retval = -EIO; | 747 | retval = -EIO; |
767 | goto err_video; | 748 | goto err_ctrl; |
768 | } | 749 | } |
769 | 750 | ||
770 | /* rds buffer configuration */ | 751 | /* rds buffer configuration */ |
771 | radio->wr_index = 0; | 752 | radio->wr_index = 0; |
772 | radio->rd_index = 0; | 753 | radio->rd_index = 0; |
773 | init_waitqueue_head(&radio->read_queue); | 754 | init_waitqueue_head(&radio->read_queue); |
755 | usb_set_intfdata(intf, radio); | ||
774 | 756 | ||
775 | /* register video device */ | 757 | /* register video device */ |
776 | retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, | 758 | retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, |
777 | radio_nr); | 759 | radio_nr); |
778 | if (retval) { | 760 | if (retval) { |
779 | dev_warn(&intf->dev, "Could not register video device\n"); | 761 | dev_warn(&intf->dev, "Could not register video device\n"); |
780 | goto err_all; | 762 | goto err_all; |
781 | } | 763 | } |
782 | usb_set_intfdata(intf, radio); | ||
783 | 764 | ||
784 | return 0; | 765 | return 0; |
785 | err_all: | 766 | err_all: |
786 | kfree(radio->buffer); | 767 | kfree(radio->buffer); |
787 | err_video: | 768 | err_ctrl: |
788 | video_device_release(radio->videodev); | 769 | v4l2_ctrl_handler_free(&radio->hdl); |
770 | err_dev: | ||
771 | v4l2_device_unregister(&radio->v4l2_dev); | ||
789 | err_urb: | 772 | err_urb: |
790 | usb_free_urb(radio->int_in_urb); | 773 | usb_free_urb(radio->int_in_urb); |
791 | err_intbuffer: | 774 | err_intbuffer: |
@@ -828,23 +811,10 @@ static void si470x_usb_driver_disconnect(struct usb_interface *intf) | |||
828 | struct si470x_device *radio = usb_get_intfdata(intf); | 811 | struct si470x_device *radio = usb_get_intfdata(intf); |
829 | 812 | ||
830 | mutex_lock(&radio->lock); | 813 | mutex_lock(&radio->lock); |
831 | radio->disconnected = 1; | 814 | v4l2_device_disconnect(&radio->v4l2_dev); |
815 | video_unregister_device(&radio->videodev); | ||
832 | usb_set_intfdata(intf, NULL); | 816 | usb_set_intfdata(intf, NULL); |
833 | if (radio->users == 0) { | 817 | mutex_unlock(&radio->lock); |
834 | /* set led to disconnect state */ | ||
835 | si470x_set_led_state(radio, BLINK_ORANGE_LED); | ||
836 | |||
837 | /* Free data structures. */ | ||
838 | usb_free_urb(radio->int_in_urb); | ||
839 | |||
840 | kfree(radio->int_in_buffer); | ||
841 | video_unregister_device(radio->videodev); | ||
842 | kfree(radio->buffer); | ||
843 | mutex_unlock(&radio->lock); | ||
844 | kfree(radio); | ||
845 | } else { | ||
846 | mutex_unlock(&radio->lock); | ||
847 | } | ||
848 | } | 818 | } |
849 | 819 | ||
850 | 820 | ||
diff --git a/drivers/media/radio/si470x/radio-si470x.h b/drivers/media/radio/si470x/radio-si470x.h index f300a55ed85c..4921cab8e0fa 100644 --- a/drivers/media/radio/si470x/radio-si470x.h +++ b/drivers/media/radio/si470x/radio-si470x.h | |||
@@ -36,6 +36,9 @@ | |||
36 | #include <linux/mutex.h> | 36 | #include <linux/mutex.h> |
37 | #include <media/v4l2-common.h> | 37 | #include <media/v4l2-common.h> |
38 | #include <media/v4l2-ioctl.h> | 38 | #include <media/v4l2-ioctl.h> |
39 | #include <media/v4l2-ctrls.h> | ||
40 | #include <media/v4l2-event.h> | ||
41 | #include <media/v4l2-device.h> | ||
39 | #include <asm/unaligned.h> | 42 | #include <asm/unaligned.h> |
40 | 43 | ||
41 | 44 | ||
@@ -141,10 +144,9 @@ | |||
141 | * si470x_device - private data | 144 | * si470x_device - private data |
142 | */ | 145 | */ |
143 | struct si470x_device { | 146 | struct si470x_device { |
144 | struct video_device *videodev; | 147 | struct v4l2_device v4l2_dev; |
145 | 148 | struct video_device videodev; | |
146 | /* driver management */ | 149 | struct v4l2_ctrl_handler hdl; |
147 | unsigned int users; | ||
148 | 150 | ||
149 | /* Silabs internal registers (0..15) */ | 151 | /* Silabs internal registers (0..15) */ |
150 | unsigned short registers[RADIO_REGISTER_NUM]; | 152 | unsigned short registers[RADIO_REGISTER_NUM]; |
@@ -174,9 +176,6 @@ struct si470x_device { | |||
174 | /* scratch page */ | 176 | /* scratch page */ |
175 | unsigned char software_version; | 177 | unsigned char software_version; |
176 | unsigned char hardware_version; | 178 | unsigned char hardware_version; |
177 | |||
178 | /* driver management */ | ||
179 | unsigned char disconnected; | ||
180 | #endif | 179 | #endif |
181 | 180 | ||
182 | #if defined(CONFIG_I2C_SI470X) || defined(CONFIG_I2C_SI470X_MODULE) | 181 | #if defined(CONFIG_I2C_SI470X) || defined(CONFIG_I2C_SI470X_MODULE) |
@@ -213,6 +212,7 @@ struct si470x_device { | |||
213 | * Common Functions | 212 | * Common Functions |
214 | **************************************************************************/ | 213 | **************************************************************************/ |
215 | extern struct video_device si470x_viddev_template; | 214 | extern struct video_device si470x_viddev_template; |
215 | extern const struct v4l2_ctrl_ops si470x_ctrl_ops; | ||
216 | int si470x_get_register(struct si470x_device *radio, int regnr); | 216 | int si470x_get_register(struct si470x_device *radio, int regnr); |
217 | int si470x_set_register(struct si470x_device *radio, int regnr); | 217 | int si470x_set_register(struct si470x_device *radio, int regnr); |
218 | int si470x_disconnect_check(struct si470x_device *radio); | 218 | int si470x_disconnect_check(struct si470x_device *radio); |