diff options
author | Hans Verkuil <hans.verkuil@cisco.com> | 2012-05-11 08:07:45 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-07-06 17:09:17 -0400 |
commit | 8c7cb12ac1cc4ecc318765e0e2dcd853fa4a4d62 (patch) | |
tree | 58c579cbffffc169bff4652fcb90f3616ef795bb /drivers | |
parent | bac639818c2c720ea8f79f932601f9209579bf14 (diff) |
[media] cx88: each device node gets the right controls
radio only sees audio controls, video sees video and audio and vbi
sees none.
Also disable the chroma_agc control if secam is selected.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/video/cx88/cx88-cards.c | 15 | ||||
-rw-r--r-- | drivers/media/video/cx88/cx88-core.c | 7 | ||||
-rw-r--r-- | drivers/media/video/cx88/cx88-video.c | 139 | ||||
-rw-r--r-- | drivers/media/video/cx88/cx88.h | 4 |
4 files changed, 108 insertions, 57 deletions
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index cd8c3bf698ea..4e9d4f722960 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c | |||
@@ -3693,14 +3693,22 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) | |||
3693 | return NULL; | 3693 | return NULL; |
3694 | } | 3694 | } |
3695 | 3695 | ||
3696 | if (v4l2_ctrl_handler_init(&core->hdl, 13)) { | 3696 | if (v4l2_ctrl_handler_init(&core->video_hdl, 13)) { |
3697 | v4l2_device_unregister(&core->v4l2_dev); | ||
3698 | kfree(core); | ||
3699 | return NULL; | ||
3700 | } | ||
3701 | |||
3702 | if (v4l2_ctrl_handler_init(&core->audio_hdl, 13)) { | ||
3703 | v4l2_ctrl_handler_free(&core->video_hdl); | ||
3697 | v4l2_device_unregister(&core->v4l2_dev); | 3704 | v4l2_device_unregister(&core->v4l2_dev); |
3698 | kfree(core); | 3705 | kfree(core); |
3699 | return NULL; | 3706 | return NULL; |
3700 | } | 3707 | } |
3701 | 3708 | ||
3702 | if (0 != cx88_get_resources(core, pci)) { | 3709 | if (0 != cx88_get_resources(core, pci)) { |
3703 | v4l2_ctrl_handler_free(&core->hdl); | 3710 | v4l2_ctrl_handler_free(&core->video_hdl); |
3711 | v4l2_ctrl_handler_free(&core->audio_hdl); | ||
3704 | v4l2_device_unregister(&core->v4l2_dev); | 3712 | v4l2_device_unregister(&core->v4l2_dev); |
3705 | kfree(core); | 3713 | kfree(core); |
3706 | return NULL; | 3714 | return NULL; |
@@ -3715,7 +3723,8 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) | |||
3715 | if (core->lmmio == NULL) { | 3723 | if (core->lmmio == NULL) { |
3716 | release_mem_region(pci_resource_start(pci, 0), | 3724 | release_mem_region(pci_resource_start(pci, 0), |
3717 | pci_resource_len(pci, 0)); | 3725 | pci_resource_len(pci, 0)); |
3718 | v4l2_ctrl_handler_free(&core->hdl); | 3726 | v4l2_ctrl_handler_free(&core->video_hdl); |
3727 | v4l2_ctrl_handler_free(&core->audio_hdl); | ||
3719 | v4l2_device_unregister(&core->v4l2_dev); | 3728 | v4l2_device_unregister(&core->v4l2_dev); |
3720 | kfree(core); | 3729 | kfree(core); |
3721 | return NULL; | 3730 | return NULL; |
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index a6480aaa8a0b..8bd925db412b 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c | |||
@@ -1012,6 +1012,9 @@ int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm) | |||
1012 | // tell i2c chips | 1012 | // tell i2c chips |
1013 | call_all(core, core, s_std, norm); | 1013 | call_all(core, core, s_std, norm); |
1014 | 1014 | ||
1015 | /* The chroma_agc control should be inaccessible if the video format is SECAM */ | ||
1016 | v4l2_ctrl_grab(core->chroma_agc, cxiformat == VideoFormatSECAM); | ||
1017 | |||
1015 | // done | 1018 | // done |
1016 | return 0; | 1019 | return 0; |
1017 | } | 1020 | } |
@@ -1030,7 +1033,6 @@ struct video_device *cx88_vdev_init(struct cx88_core *core, | |||
1030 | return NULL; | 1033 | return NULL; |
1031 | *vfd = *template_; | 1034 | *vfd = *template_; |
1032 | vfd->v4l2_dev = &core->v4l2_dev; | 1035 | vfd->v4l2_dev = &core->v4l2_dev; |
1033 | vfd->ctrl_handler = &core->hdl; | ||
1034 | vfd->release = video_device_release; | 1036 | vfd->release = video_device_release; |
1035 | snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", | 1037 | snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", |
1036 | core->name, type, core->board.name); | 1038 | core->name, type, core->board.name); |
@@ -1086,7 +1088,8 @@ void cx88_core_put(struct cx88_core *core, struct pci_dev *pci) | |||
1086 | iounmap(core->lmmio); | 1088 | iounmap(core->lmmio); |
1087 | cx88_devcount--; | 1089 | cx88_devcount--; |
1088 | mutex_unlock(&devlist); | 1090 | mutex_unlock(&devlist); |
1089 | v4l2_ctrl_handler_free(&core->hdl); | 1091 | v4l2_ctrl_handler_free(&core->video_hdl); |
1092 | v4l2_ctrl_handler_free(&core->audio_hdl); | ||
1090 | v4l2_device_unregister(&core->v4l2_dev); | 1093 | v4l2_device_unregister(&core->v4l2_dev); |
1091 | kfree(core); | 1094 | kfree(core); |
1092 | } | 1095 | } |
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 2f3d4df33f7e..104a85c265f3 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c | |||
@@ -155,12 +155,6 @@ static const struct cx8800_fmt* format_by_fourcc(unsigned int fourcc) | |||
155 | 155 | ||
156 | /* ------------------------------------------------------------------- */ | 156 | /* ------------------------------------------------------------------- */ |
157 | 157 | ||
158 | static const struct v4l2_queryctrl no_ctl = { | ||
159 | .name = "42", | ||
160 | .flags = V4L2_CTRL_FLAG_DISABLED, | ||
161 | }; | ||
162 | |||
163 | |||
164 | struct cx88_ctrl { | 158 | struct cx88_ctrl { |
165 | /* control information */ | 159 | /* control information */ |
166 | u32 id; | 160 | u32 id; |
@@ -177,7 +171,7 @@ struct cx88_ctrl { | |||
177 | u32 shift; | 171 | u32 shift; |
178 | }; | 172 | }; |
179 | 173 | ||
180 | static const struct cx88_ctrl cx8800_ctls[] = { | 174 | static const struct cx88_ctrl cx8800_vid_ctls[] = { |
181 | /* --- video --- */ | 175 | /* --- video --- */ |
182 | { | 176 | { |
183 | .id = V4L2_CID_BRIGHTNESS, | 177 | .id = V4L2_CID_BRIGHTNESS, |
@@ -260,7 +254,11 @@ static const struct cx88_ctrl cx8800_ctls[] = { | |||
260 | .reg = MO_HTOTAL, | 254 | .reg = MO_HTOTAL, |
261 | .mask = 3 << 11, | 255 | .mask = 3 << 11, |
262 | .shift = 11, | 256 | .shift = 11, |
263 | }, { | 257 | } |
258 | }; | ||
259 | |||
260 | static const struct cx88_ctrl cx8800_aud_ctls[] = { | ||
261 | { | ||
264 | /* --- audio --- */ | 262 | /* --- audio --- */ |
265 | .id = V4L2_CID_AUDIO_MUTE, | 263 | .id = V4L2_CID_AUDIO_MUTE, |
266 | .minimum = 0, | 264 | .minimum = 0, |
@@ -293,14 +291,10 @@ static const struct cx88_ctrl cx8800_ctls[] = { | |||
293 | } | 291 | } |
294 | }; | 292 | }; |
295 | 293 | ||
296 | enum { CX8800_CTLS = ARRAY_SIZE(cx8800_ctls) }; | 294 | enum { |
297 | 295 | CX8800_VID_CTLS = ARRAY_SIZE(cx8800_vid_ctls), | |
298 | 296 | CX8800_AUD_CTLS = ARRAY_SIZE(cx8800_aud_ctls), | |
299 | int cx8800_ctrl_query(struct cx88_core *core, struct v4l2_queryctrl *qctrl) | 297 | }; |
300 | { | ||
301 | return 0; | ||
302 | } | ||
303 | EXPORT_SYMBOL(cx8800_ctrl_query); | ||
304 | 298 | ||
305 | /* ------------------------------------------------------------------- */ | 299 | /* ------------------------------------------------------------------- */ |
306 | /* resource management */ | 300 | /* resource management */ |
@@ -908,10 +902,56 @@ video_mmap(struct file *file, struct vm_area_struct * vma) | |||
908 | /* ------------------------------------------------------------------ */ | 902 | /* ------------------------------------------------------------------ */ |
909 | /* VIDEO CTRL IOCTLS */ | 903 | /* VIDEO CTRL IOCTLS */ |
910 | 904 | ||
911 | static int cx8800_s_ctrl(struct v4l2_ctrl *ctrl) | 905 | static int cx8800_s_vid_ctrl(struct v4l2_ctrl *ctrl) |
906 | { | ||
907 | struct cx88_core *core = | ||
908 | container_of(ctrl->handler, struct cx88_core, video_hdl); | ||
909 | const struct cx88_ctrl *cc = ctrl->priv; | ||
910 | u32 value, mask; | ||
911 | |||
912 | mask = cc->mask; | ||
913 | switch (ctrl->id) { | ||
914 | case V4L2_CID_SATURATION: | ||
915 | /* special v_sat handling */ | ||
916 | |||
917 | value = ((ctrl->val - cc->off) << cc->shift) & cc->mask; | ||
918 | |||
919 | if (core->tvnorm & V4L2_STD_SECAM) { | ||
920 | /* For SECAM, both U and V sat should be equal */ | ||
921 | value = value << 8 | value; | ||
922 | } else { | ||
923 | /* Keeps U Saturation proportional to V Sat */ | ||
924 | value = (value * 0x5a) / 0x7f << 8 | value; | ||
925 | } | ||
926 | mask = 0xffff; | ||
927 | break; | ||
928 | case V4L2_CID_SHARPNESS: | ||
929 | /* 0b000, 0b100, 0b101, 0b110, or 0b111 */ | ||
930 | value = (ctrl->val < 1 ? 0 : ((ctrl->val + 3) << 7)); | ||
931 | /* needs to be set for both fields */ | ||
932 | cx_andor(MO_FILTER_EVEN, mask, value); | ||
933 | break; | ||
934 | case V4L2_CID_CHROMA_AGC: | ||
935 | value = ((ctrl->val - cc->off) << cc->shift) & cc->mask; | ||
936 | break; | ||
937 | default: | ||
938 | value = ((ctrl->val - cc->off) << cc->shift) & cc->mask; | ||
939 | break; | ||
940 | } | ||
941 | dprintk(1, "set_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n", | ||
942 | ctrl->id, ctrl->name, ctrl->val, cc->reg, value, | ||
943 | mask, cc->sreg ? " [shadowed]" : ""); | ||
944 | if (cc->sreg) | ||
945 | cx_sandor(cc->sreg, cc->reg, mask, value); | ||
946 | else | ||
947 | cx_andor(cc->reg, mask, value); | ||
948 | return 0; | ||
949 | } | ||
950 | |||
951 | static int cx8800_s_aud_ctrl(struct v4l2_ctrl *ctrl) | ||
912 | { | 952 | { |
913 | struct cx88_core *core = | 953 | struct cx88_core *core = |
914 | container_of(ctrl->handler, struct cx88_core, hdl); | 954 | container_of(ctrl->handler, struct cx88_core, audio_hdl); |
915 | const struct cx88_ctrl *cc = ctrl->priv; | 955 | const struct cx88_ctrl *cc = ctrl->priv; |
916 | u32 value,mask; | 956 | u32 value,mask; |
917 | 957 | ||
@@ -941,32 +981,6 @@ static int cx8800_s_ctrl(struct v4l2_ctrl *ctrl) | |||
941 | case V4L2_CID_AUDIO_VOLUME: | 981 | case V4L2_CID_AUDIO_VOLUME: |
942 | value = 0x3f - (ctrl->val & 0x3f); | 982 | value = 0x3f - (ctrl->val & 0x3f); |
943 | break; | 983 | break; |
944 | case V4L2_CID_SATURATION: | ||
945 | /* special v_sat handling */ | ||
946 | |||
947 | value = ((ctrl->val - cc->off) << cc->shift) & cc->mask; | ||
948 | |||
949 | if (core->tvnorm & V4L2_STD_SECAM) { | ||
950 | /* For SECAM, both U and V sat should be equal */ | ||
951 | value=value<<8|value; | ||
952 | } else { | ||
953 | /* Keeps U Saturation proportional to V Sat */ | ||
954 | value=(value*0x5a)/0x7f<<8|value; | ||
955 | } | ||
956 | mask=0xffff; | ||
957 | break; | ||
958 | case V4L2_CID_SHARPNESS: | ||
959 | /* 0b000, 0b100, 0b101, 0b110, or 0b111 */ | ||
960 | value = (ctrl->val < 1 ? 0 : ((ctrl->val + 3) << 7)); | ||
961 | /* needs to be set for both fields */ | ||
962 | cx_andor(MO_FILTER_EVEN, mask, value); | ||
963 | break; | ||
964 | case V4L2_CID_CHROMA_AGC: | ||
965 | /* Do not allow chroma AGC to be enabled for SECAM */ | ||
966 | value = ((ctrl->val - cc->off) << cc->shift) & cc->mask; | ||
967 | if ((core->tvnorm & V4L2_STD_SECAM) && value) | ||
968 | return -EINVAL; | ||
969 | break; | ||
970 | default: | 984 | default: |
971 | value = ((ctrl->val - cc->off) << cc->shift) & cc->mask; | 985 | value = ((ctrl->val - cc->off) << cc->shift) & cc->mask; |
972 | break; | 986 | break; |
@@ -1599,8 +1613,12 @@ static const struct video_device cx8800_radio_template = { | |||
1599 | .ioctl_ops = &radio_ioctl_ops, | 1613 | .ioctl_ops = &radio_ioctl_ops, |
1600 | }; | 1614 | }; |
1601 | 1615 | ||
1602 | static const struct v4l2_ctrl_ops cx8800_ctrl_ops = { | 1616 | static const struct v4l2_ctrl_ops cx8800_ctrl_vid_ops = { |
1603 | .s_ctrl = cx8800_s_ctrl, | 1617 | .s_ctrl = cx8800_s_vid_ctrl, |
1618 | }; | ||
1619 | |||
1620 | static const struct v4l2_ctrl_ops cx8800_ctrl_aud_ops = { | ||
1621 | .s_ctrl = cx8800_s_aud_ctrl, | ||
1604 | }; | 1622 | }; |
1605 | 1623 | ||
1606 | /* ----------------------------------------------------------- */ | 1624 | /* ----------------------------------------------------------- */ |
@@ -1707,18 +1725,34 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, | |||
1707 | } | 1725 | } |
1708 | cx_set(MO_PCI_INTMSK, core->pci_irqmask); | 1726 | cx_set(MO_PCI_INTMSK, core->pci_irqmask); |
1709 | 1727 | ||
1710 | for (i = 0; i < CX8800_CTLS; i++) { | 1728 | for (i = 0; i < CX8800_AUD_CTLS; i++) { |
1711 | const struct cx88_ctrl *cc = &cx8800_ctls[i]; | 1729 | const struct cx88_ctrl *cc = &cx8800_aud_ctls[i]; |
1730 | struct v4l2_ctrl *vc; | ||
1731 | |||
1732 | vc = v4l2_ctrl_new_std(&core->audio_hdl, &cx8800_ctrl_aud_ops, | ||
1733 | cc->id, cc->minimum, cc->maximum, cc->step, cc->default_value); | ||
1734 | if (vc == NULL) { | ||
1735 | err = core->audio_hdl.error; | ||
1736 | goto fail_core; | ||
1737 | } | ||
1738 | vc->priv = (void *)cc; | ||
1739 | } | ||
1740 | |||
1741 | for (i = 0; i < CX8800_VID_CTLS; i++) { | ||
1742 | const struct cx88_ctrl *cc = &cx8800_vid_ctls[i]; | ||
1712 | struct v4l2_ctrl *vc; | 1743 | struct v4l2_ctrl *vc; |
1713 | 1744 | ||
1714 | vc = v4l2_ctrl_new_std(&core->hdl, &cx8800_ctrl_ops, | 1745 | vc = v4l2_ctrl_new_std(&core->video_hdl, &cx8800_ctrl_vid_ops, |
1715 | cc->id, cc->minimum, cc->maximum, cc->step, cc->default_value); | 1746 | cc->id, cc->minimum, cc->maximum, cc->step, cc->default_value); |
1716 | if (vc == NULL) { | 1747 | if (vc == NULL) { |
1717 | err = core->hdl.error; | 1748 | err = core->video_hdl.error; |
1718 | goto fail_core; | 1749 | goto fail_core; |
1719 | } | 1750 | } |
1720 | vc->priv = (void *)cc; | 1751 | vc->priv = (void *)cc; |
1752 | if (vc->id == V4L2_CID_CHROMA_AGC) | ||
1753 | core->chroma_agc = vc; | ||
1721 | } | 1754 | } |
1755 | v4l2_ctrl_add_handler(&core->video_hdl, &core->audio_hdl); | ||
1722 | 1756 | ||
1723 | /* load and configure helper modules */ | 1757 | /* load and configure helper modules */ |
1724 | 1758 | ||
@@ -1771,13 +1805,15 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, | |||
1771 | /* initial device configuration */ | 1805 | /* initial device configuration */ |
1772 | mutex_lock(&core->lock); | 1806 | mutex_lock(&core->lock); |
1773 | cx88_set_tvnorm(core, core->tvnorm); | 1807 | cx88_set_tvnorm(core, core->tvnorm); |
1774 | v4l2_ctrl_handler_setup(&core->hdl); | 1808 | v4l2_ctrl_handler_setup(&core->video_hdl); |
1809 | v4l2_ctrl_handler_setup(&core->audio_hdl); | ||
1775 | cx88_video_mux(core, 0); | 1810 | cx88_video_mux(core, 0); |
1776 | 1811 | ||
1777 | /* register v4l devices */ | 1812 | /* register v4l devices */ |
1778 | dev->video_dev = cx88_vdev_init(core,dev->pci, | 1813 | dev->video_dev = cx88_vdev_init(core,dev->pci, |
1779 | &cx8800_video_template,"video"); | 1814 | &cx8800_video_template,"video"); |
1780 | video_set_drvdata(dev->video_dev, dev); | 1815 | video_set_drvdata(dev->video_dev, dev); |
1816 | dev->video_dev->ctrl_handler = &core->video_hdl; | ||
1781 | err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER, | 1817 | err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER, |
1782 | video_nr[core->nr]); | 1818 | video_nr[core->nr]); |
1783 | if (err < 0) { | 1819 | if (err < 0) { |
@@ -1804,6 +1840,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, | |||
1804 | dev->radio_dev = cx88_vdev_init(core,dev->pci, | 1840 | dev->radio_dev = cx88_vdev_init(core,dev->pci, |
1805 | &cx8800_radio_template,"radio"); | 1841 | &cx8800_radio_template,"radio"); |
1806 | video_set_drvdata(dev->radio_dev, dev); | 1842 | video_set_drvdata(dev->radio_dev, dev); |
1843 | dev->radio_dev->ctrl_handler = &core->audio_hdl; | ||
1807 | err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO, | 1844 | err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO, |
1808 | radio_nr[core->nr]); | 1845 | radio_nr[core->nr]); |
1809 | if (err < 0) { | 1846 | if (err < 0) { |
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index f12a77b4532d..280bf6ab7b75 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h | |||
@@ -350,7 +350,9 @@ struct cx88_core { | |||
350 | 350 | ||
351 | /* config info -- analog */ | 351 | /* config info -- analog */ |
352 | struct v4l2_device v4l2_dev; | 352 | struct v4l2_device v4l2_dev; |
353 | struct v4l2_ctrl_handler hdl; | 353 | struct v4l2_ctrl_handler video_hdl; |
354 | struct v4l2_ctrl *chroma_agc; | ||
355 | struct v4l2_ctrl_handler audio_hdl; | ||
354 | struct v4l2_subdev *sd_wm8775; | 356 | struct v4l2_subdev *sd_wm8775; |
355 | struct i2c_client *i2c_rtc; | 357 | struct i2c_client *i2c_rtc; |
356 | unsigned int boardnr; | 358 | unsigned int boardnr; |