diff options
Diffstat (limited to 'drivers/media/video/em28xx/em28xx-video.c')
-rw-r--r-- | drivers/media/video/em28xx/em28xx-video.c | 167 |
1 files changed, 127 insertions, 40 deletions
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 3a56120397ae..fdc255918dde 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c | |||
@@ -32,6 +32,7 @@ | |||
32 | 32 | ||
33 | #include "em28xx.h" | 33 | #include "em28xx.h" |
34 | #include <media/tuner.h> | 34 | #include <media/tuner.h> |
35 | #include <media/v4l2-common.h> | ||
35 | 36 | ||
36 | #define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \ | 37 | #define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \ |
37 | "Markus Rechberger <mrechberger@gmail.com>, " \ | 38 | "Markus Rechberger <mrechberger@gmail.com>, " \ |
@@ -106,8 +107,32 @@ static const unsigned char saa7114_i2c_init[] = { | |||
106 | #define TVNORMS ARRAY_SIZE(tvnorms) | 107 | #define TVNORMS ARRAY_SIZE(tvnorms) |
107 | 108 | ||
108 | /* supported controls */ | 109 | /* supported controls */ |
110 | /* Common to all boards */ | ||
109 | static struct v4l2_queryctrl em28xx_qctrl[] = { | 111 | static struct v4l2_queryctrl em28xx_qctrl[] = { |
110 | { | 112 | { |
113 | .id = V4L2_CID_AUDIO_VOLUME, | ||
114 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
115 | .name = "Volume", | ||
116 | .minimum = 0x0, | ||
117 | .maximum = 0x1f, | ||
118 | .step = 0x1, | ||
119 | .default_value = 0x1f, | ||
120 | .flags = 0, | ||
121 | },{ | ||
122 | .id = V4L2_CID_AUDIO_MUTE, | ||
123 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
124 | .name = "Mute", | ||
125 | .minimum = 0, | ||
126 | .maximum = 1, | ||
127 | .step = 1, | ||
128 | .default_value = 1, | ||
129 | .flags = 0, | ||
130 | } | ||
131 | }; | ||
132 | |||
133 | /* FIXME: These are specific to saa711x - should be moved to its code */ | ||
134 | static struct v4l2_queryctrl saa711x_qctrl[] = { | ||
135 | { | ||
111 | .id = V4L2_CID_BRIGHTNESS, | 136 | .id = V4L2_CID_BRIGHTNESS, |
112 | .type = V4L2_CTRL_TYPE_INTEGER, | 137 | .type = V4L2_CTRL_TYPE_INTEGER, |
113 | .name = "Brightness", | 138 | .name = "Brightness", |
@@ -135,24 +160,6 @@ static struct v4l2_queryctrl em28xx_qctrl[] = { | |||
135 | .default_value = 0x10, | 160 | .default_value = 0x10, |
136 | .flags = 0, | 161 | .flags = 0, |
137 | },{ | 162 | },{ |
138 | .id = V4L2_CID_AUDIO_VOLUME, | ||
139 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
140 | .name = "Volume", | ||
141 | .minimum = 0x0, | ||
142 | .maximum = 0x1f, | ||
143 | .step = 0x1, | ||
144 | .default_value = 0x1f, | ||
145 | .flags = 0, | ||
146 | },{ | ||
147 | .id = V4L2_CID_AUDIO_MUTE, | ||
148 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
149 | .name = "Mute", | ||
150 | .minimum = 0, | ||
151 | .maximum = 1, | ||
152 | .step = 1, | ||
153 | .default_value = 1, | ||
154 | .flags = 0, | ||
155 | },{ | ||
156 | .id = V4L2_CID_RED_BALANCE, | 163 | .id = V4L2_CID_RED_BALANCE, |
157 | .type = V4L2_CTRL_TYPE_INTEGER, | 164 | .type = V4L2_CTRL_TYPE_INTEGER, |
158 | .name = "Red chroma balance", | 165 | .name = "Red chroma balance", |
@@ -179,7 +186,7 @@ static struct v4l2_queryctrl em28xx_qctrl[] = { | |||
179 | .step = 0x1, | 186 | .step = 0x1, |
180 | .default_value = 0x20, | 187 | .default_value = 0x20, |
181 | .flags = 0, | 188 | .flags = 0, |
182 | } | 189 | } |
183 | }; | 190 | }; |
184 | 191 | ||
185 | static struct usb_driver em28xx_usb_driver; | 192 | static struct usb_driver em28xx_usb_driver; |
@@ -280,6 +287,8 @@ static void video_mux(struct em28xx *dev, int index) | |||
280 | em28xx_videodbg("Setting input index=%d, vmux=%d, amux=%d\n",index,input,dev->ctl_ainput); | 287 | em28xx_videodbg("Setting input index=%d, vmux=%d, amux=%d\n",index,input,dev->ctl_ainput); |
281 | 288 | ||
282 | if (dev->has_msp34xx) { | 289 | if (dev->has_msp34xx) { |
290 | if (dev->i2s_speed) | ||
291 | em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ, &dev->i2s_speed); | ||
283 | em28xx_i2c_call_clients(dev, VIDIOC_S_AUDIO, &dev->ctl_ainput); | 292 | em28xx_i2c_call_clients(dev, VIDIOC_S_AUDIO, &dev->ctl_ainput); |
284 | ainput = EM28XX_AUDIO_SRC_TUNER; | 293 | ainput = EM28XX_AUDIO_SRC_TUNER; |
285 | em28xx_audio_source(dev, ainput); | 294 | em28xx_audio_source(dev, ainput); |
@@ -674,7 +683,6 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) | |||
674 | */ | 683 | */ |
675 | static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl) | 684 | static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl) |
676 | { | 685 | { |
677 | s32 tmp; | ||
678 | switch (ctrl->id) { | 686 | switch (ctrl->id) { |
679 | case V4L2_CID_AUDIO_MUTE: | 687 | case V4L2_CID_AUDIO_MUTE: |
680 | ctrl->value = dev->mute; | 688 | ctrl->value = dev->mute; |
@@ -682,6 +690,16 @@ static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl) | |||
682 | case V4L2_CID_AUDIO_VOLUME: | 690 | case V4L2_CID_AUDIO_VOLUME: |
683 | ctrl->value = dev->volume; | 691 | ctrl->value = dev->volume; |
684 | return 0; | 692 | return 0; |
693 | default: | ||
694 | return -EINVAL; | ||
695 | } | ||
696 | } | ||
697 | |||
698 | /*FIXME: should be moved to saa711x */ | ||
699 | static int saa711x_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl) | ||
700 | { | ||
701 | s32 tmp; | ||
702 | switch (ctrl->id) { | ||
685 | case V4L2_CID_BRIGHTNESS: | 703 | case V4L2_CID_BRIGHTNESS: |
686 | if ((tmp = em28xx_brightness_get(dev)) < 0) | 704 | if ((tmp = em28xx_brightness_get(dev)) < 0) |
687 | return -EIO; | 705 | return -EIO; |
@@ -731,6 +749,15 @@ static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl) | |||
731 | case V4L2_CID_AUDIO_VOLUME: | 749 | case V4L2_CID_AUDIO_VOLUME: |
732 | dev->volume = ctrl->value; | 750 | dev->volume = ctrl->value; |
733 | return em28xx_audio_analog_set(dev); | 751 | return em28xx_audio_analog_set(dev); |
752 | default: | ||
753 | return -EINVAL; | ||
754 | } | ||
755 | } | ||
756 | |||
757 | /*FIXME: should be moved to saa711x */ | ||
758 | static int saa711x_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl) | ||
759 | { | ||
760 | switch (ctrl->id) { | ||
734 | case V4L2_CID_BRIGHTNESS: | 761 | case V4L2_CID_BRIGHTNESS: |
735 | return em28xx_brightness_set(dev, ctrl->value); | 762 | return em28xx_brightness_set(dev, ctrl->value); |
736 | case V4L2_CID_CONTRAST: | 763 | case V4L2_CID_CONTRAST: |
@@ -994,14 +1021,34 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp, | |||
994 | case VIDIOC_QUERYCTRL: | 1021 | case VIDIOC_QUERYCTRL: |
995 | { | 1022 | { |
996 | struct v4l2_queryctrl *qc = arg; | 1023 | struct v4l2_queryctrl *qc = arg; |
997 | u8 i, n; | 1024 | int i, id=qc->id; |
998 | n = sizeof(em28xx_qctrl) / sizeof(em28xx_qctrl[0]); | 1025 | |
999 | for (i = 0; i < n; i++) | 1026 | memset(qc,0,sizeof(*qc)); |
1000 | if (qc->id && qc->id == em28xx_qctrl[i].id) { | 1027 | qc->id=id; |
1001 | memcpy(qc, &(em28xx_qctrl[i]), | 1028 | |
1029 | if (!dev->has_msp34xx) { | ||
1030 | for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { | ||
1031 | if (qc->id && qc->id == em28xx_qctrl[i].id) { | ||
1032 | memcpy(qc, &(em28xx_qctrl[i]), | ||
1033 | sizeof(*qc)); | ||
1034 | return 0; | ||
1035 | } | ||
1036 | } | ||
1037 | } | ||
1038 | if (dev->decoder == EM28XX_TVP5150) { | ||
1039 | em28xx_i2c_call_clients(dev,cmd,qc); | ||
1040 | if (qc->type) | ||
1041 | return 0; | ||
1042 | else | ||
1043 | return -EINVAL; | ||
1044 | } | ||
1045 | for (i = 0; i < ARRAY_SIZE(saa711x_qctrl); i++) { | ||
1046 | if (qc->id && qc->id == saa711x_qctrl[i].id) { | ||
1047 | memcpy(qc, &(saa711x_qctrl[i]), | ||
1002 | sizeof(*qc)); | 1048 | sizeof(*qc)); |
1003 | return 0; | 1049 | return 0; |
1004 | } | 1050 | } |
1051 | } | ||
1005 | 1052 | ||
1006 | return -EINVAL; | 1053 | return -EINVAL; |
1007 | } | 1054 | } |
@@ -1009,29 +1056,64 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp, | |||
1009 | case VIDIOC_G_CTRL: | 1056 | case VIDIOC_G_CTRL: |
1010 | { | 1057 | { |
1011 | struct v4l2_control *ctrl = arg; | 1058 | struct v4l2_control *ctrl = arg; |
1059 | int retval=-EINVAL; | ||
1012 | 1060 | ||
1061 | if (!dev->has_msp34xx) | ||
1062 | retval=em28xx_get_ctrl(dev, ctrl); | ||
1063 | if (retval==-EINVAL) { | ||
1064 | if (dev->decoder == EM28XX_TVP5150) { | ||
1065 | em28xx_i2c_call_clients(dev,cmd,arg); | ||
1066 | return 0; | ||
1067 | } | ||
1013 | 1068 | ||
1014 | return em28xx_get_ctrl(dev, ctrl); | 1069 | return saa711x_get_ctrl(dev, ctrl); |
1070 | } else return retval; | ||
1015 | } | 1071 | } |
1016 | 1072 | ||
1017 | case VIDIOC_S_CTRL_OLD: /* ??? */ | ||
1018 | case VIDIOC_S_CTRL: | 1073 | case VIDIOC_S_CTRL: |
1019 | { | 1074 | { |
1020 | struct v4l2_control *ctrl = arg; | 1075 | struct v4l2_control *ctrl = arg; |
1021 | u8 i, n; | 1076 | u8 i; |
1022 | 1077 | ||
1023 | 1078 | if (!dev->has_msp34xx){ | |
1024 | n = sizeof(em28xx_qctrl) / sizeof(em28xx_qctrl[0]); | 1079 | for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { |
1025 | for (i = 0; i < n; i++) | 1080 | if (ctrl->id == em28xx_qctrl[i].id) { |
1026 | if (ctrl->id == em28xx_qctrl[i].id) { | 1081 | if (ctrl->value < |
1027 | if (ctrl->value < | 1082 | em28xx_qctrl[i].minimum |
1028 | em28xx_qctrl[i].minimum | 1083 | || ctrl->value > |
1029 | || ctrl->value > | 1084 | em28xx_qctrl[i].maximum) |
1030 | em28xx_qctrl[i].maximum) | 1085 | return -ERANGE; |
1031 | return -ERANGE; | 1086 | return em28xx_set_ctrl(dev, ctrl); |
1087 | } | ||
1088 | } | ||
1089 | } | ||
1032 | 1090 | ||
1033 | return em28xx_set_ctrl(dev, ctrl); | 1091 | if (dev->decoder == EM28XX_TVP5150) { |
1092 | em28xx_i2c_call_clients(dev,cmd,arg); | ||
1093 | return 0; | ||
1094 | } else if (!dev->has_msp34xx) { | ||
1095 | for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { | ||
1096 | if (ctrl->id == em28xx_qctrl[i].id) { | ||
1097 | if (ctrl->value < | ||
1098 | em28xx_qctrl[i].minimum | ||
1099 | || ctrl->value > | ||
1100 | em28xx_qctrl[i].maximum) | ||
1101 | return -ERANGE; | ||
1102 | return em28xx_set_ctrl(dev, ctrl); | ||
1103 | } | ||
1034 | } | 1104 | } |
1105 | for (i = 0; i < ARRAY_SIZE(saa711x_qctrl); i++) { | ||
1106 | if (ctrl->id == saa711x_qctrl[i].id) { | ||
1107 | if (ctrl->value < | ||
1108 | saa711x_qctrl[i].minimum | ||
1109 | || ctrl->value > | ||
1110 | saa711x_qctrl[i].maximum) | ||
1111 | return -ERANGE; | ||
1112 | return saa711x_set_ctrl(dev, ctrl); | ||
1113 | } | ||
1114 | } | ||
1115 | } | ||
1116 | |||
1035 | return -EINVAL; | 1117 | return -EINVAL; |
1036 | } | 1118 | } |
1037 | 1119 | ||
@@ -1187,7 +1269,7 @@ static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp, | |||
1187 | return -ENODEV; | 1269 | return -ENODEV; |
1188 | 1270 | ||
1189 | if (video_debug > 1) | 1271 | if (video_debug > 1) |
1190 | em28xx_print_ioctl(dev->name,cmd); | 1272 | v4l_print_ioctl(dev->name,cmd); |
1191 | 1273 | ||
1192 | switch (cmd) { | 1274 | switch (cmd) { |
1193 | 1275 | ||
@@ -1564,6 +1646,8 @@ static struct file_operations em28xx_v4l_fops = { | |||
1564 | .poll = em28xx_v4l2_poll, | 1646 | .poll = em28xx_v4l2_poll, |
1565 | .mmap = em28xx_v4l2_mmap, | 1647 | .mmap = em28xx_v4l2_mmap, |
1566 | .llseek = no_llseek, | 1648 | .llseek = no_llseek, |
1649 | .compat_ioctl = v4l_compat_ioctl32, | ||
1650 | |||
1567 | }; | 1651 | }; |
1568 | 1652 | ||
1569 | /******************************** usb interface *****************************************/ | 1653 | /******************************** usb interface *****************************************/ |
@@ -1848,9 +1932,12 @@ static void em28xx_usb_disconnect(struct usb_interface *interface) | |||
1848 | struct em28xx *dev = usb_get_intfdata(interface); | 1932 | struct em28xx *dev = usb_get_intfdata(interface); |
1849 | usb_set_intfdata(interface, NULL); | 1933 | usb_set_intfdata(interface, NULL); |
1850 | 1934 | ||
1935 | /*FIXME: IR should be disconnected */ | ||
1936 | |||
1851 | if (!dev) | 1937 | if (!dev) |
1852 | return; | 1938 | return; |
1853 | 1939 | ||
1940 | |||
1854 | down_write(&em28xx_disconnect); | 1941 | down_write(&em28xx_disconnect); |
1855 | 1942 | ||
1856 | down(&dev->lock); | 1943 | down(&dev->lock); |