aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil@xs4all.nl>2006-06-18 12:43:28 -0400
committerMauro Carvalho Chehab <mchehab@infradead.org>2006-06-25 01:05:21 -0400
commit0597691456cf3b08974d9949e4caa830e1d3c520 (patch)
treee70e6b89eb1d5dad01bd5f58ef715a72efbfba13
parent4f341712120abde54d9113856e9118e6580d7061 (diff)
V4L/DVB (4189): Add videodev support for VIDIOC_S/G/TRY_EXT_CTRLS.
videodev.c copies the control list specified in struct v4l2_ext_controls to kernel space. Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
-rw-r--r--drivers/media/video/videodev.c105
-rw-r--r--include/media/v4l2-dev.h6
2 files changed, 109 insertions, 2 deletions
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
index 43152297e6d5..763e178555d0 100644
--- a/drivers/media/video/videodev.c
+++ b/drivers/media/video/videodev.c
@@ -190,10 +190,15 @@ video_usercopy(struct inode *inode, struct file *file,
190 void *mbuf = NULL; 190 void *mbuf = NULL;
191 void *parg = NULL; 191 void *parg = NULL;
192 int err = -EINVAL; 192 int err = -EINVAL;
193 int is_ext_ctrl;
194 size_t ctrls_size = 0;
195 void __user *user_ptr = NULL;
193 196
194#ifdef __OLD_VIDIOC_ 197#ifdef __OLD_VIDIOC_
195 cmd = video_fix_command(cmd); 198 cmd = video_fix_command(cmd);
196#endif 199#endif
200 is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||
201 cmd == VIDIOC_TRY_EXT_CTRLS);
197 202
198 /* Copy arguments into temp kernel buffer */ 203 /* Copy arguments into temp kernel buffer */
199 switch (_IOC_DIR(cmd)) { 204 switch (_IOC_DIR(cmd)) {
@@ -215,19 +220,47 @@ video_usercopy(struct inode *inode, struct file *file,
215 220
216 err = -EFAULT; 221 err = -EFAULT;
217 if (_IOC_DIR(cmd) & _IOC_WRITE) 222 if (_IOC_DIR(cmd) & _IOC_WRITE)
218 if (copy_from_user(parg, (void __user *)arg, 223 if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
219 _IOC_SIZE(cmd)))
220 goto out; 224 goto out;
221 break; 225 break;
222 } 226 }
227 if (is_ext_ctrl) {
228 struct v4l2_ext_controls *p = parg;
229
230 /* In case of an error, tell the caller that it wasn't
231 a specific control that caused it. */
232 p->error_idx = p->count;
233 user_ptr = (void __user *)p->controls;
234 if (p->count) {
235 ctrls_size = sizeof(struct v4l2_ext_control) * p->count;
236 /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */
237 mbuf = kmalloc(ctrls_size, GFP_KERNEL);
238 err = -ENOMEM;
239 if (NULL == mbuf)
240 goto out_ext_ctrl;
241 err = -EFAULT;
242 if (copy_from_user(mbuf, user_ptr, ctrls_size))
243 goto out_ext_ctrl;
244 p->controls = mbuf;
245 }
246 }
223 247
224 /* call driver */ 248 /* call driver */
225 err = func(inode, file, cmd, parg); 249 err = func(inode, file, cmd, parg);
226 if (err == -ENOIOCTLCMD) 250 if (err == -ENOIOCTLCMD)
227 err = -EINVAL; 251 err = -EINVAL;
252 if (is_ext_ctrl) {
253 struct v4l2_ext_controls *p = parg;
254
255 p->controls = (void *)user_ptr;
256 if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size))
257 err = -EFAULT;
258 goto out_ext_ctrl;
259 }
228 if (err < 0) 260 if (err < 0)
229 goto out; 261 goto out;
230 262
263out_ext_ctrl:
231 /* Copy results into user buffer */ 264 /* Copy results into user buffer */
232 switch (_IOC_DIR(cmd)) 265 switch (_IOC_DIR(cmd))
233 { 266 {
@@ -993,6 +1026,39 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
993 ret=vfd->vidioc_s_ctrl(file, fh, p); 1026 ret=vfd->vidioc_s_ctrl(file, fh, p);
994 break; 1027 break;
995 } 1028 }
1029 case VIDIOC_G_EXT_CTRLS:
1030 {
1031 struct v4l2_ext_controls *p = arg;
1032
1033 if (vfd->vidioc_g_ext_ctrls) {
1034 dbgarg(cmd, "count=%d\n", p->count);
1035
1036 ret=vfd->vidioc_g_ext_ctrls(file, fh, p);
1037 }
1038 break;
1039 }
1040 case VIDIOC_S_EXT_CTRLS:
1041 {
1042 struct v4l2_ext_controls *p = arg;
1043
1044 if (vfd->vidioc_s_ext_ctrls) {
1045 dbgarg(cmd, "count=%d\n", p->count);
1046
1047 ret=vfd->vidioc_s_ext_ctrls(file, fh, p);
1048 }
1049 break;
1050 }
1051 case VIDIOC_TRY_EXT_CTRLS:
1052 {
1053 struct v4l2_ext_controls *p = arg;
1054
1055 if (vfd->vidioc_try_ext_ctrls) {
1056 dbgarg(cmd, "count=%d\n", p->count);
1057
1058 ret=vfd->vidioc_try_ext_ctrls(file, fh, p);
1059 }
1060 break;
1061 }
996 case VIDIOC_QUERYMENU: 1062 case VIDIOC_QUERYMENU:
997 { 1063 {
998 struct v4l2_querymenu *p=arg; 1064 struct v4l2_querymenu *p=arg;
@@ -1326,10 +1392,15 @@ int video_ioctl2 (struct inode *inode, struct file *file,
1326 void *mbuf = NULL; 1392 void *mbuf = NULL;
1327 void *parg = NULL; 1393 void *parg = NULL;
1328 int err = -EINVAL; 1394 int err = -EINVAL;
1395 int is_ext_ctrl;
1396 size_t ctrls_size = 0;
1397 void __user *user_ptr = NULL;
1329 1398
1330#ifdef __OLD_VIDIOC_ 1399#ifdef __OLD_VIDIOC_
1331 cmd = video_fix_command(cmd); 1400 cmd = video_fix_command(cmd);
1332#endif 1401#endif
1402 is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||
1403 cmd == VIDIOC_TRY_EXT_CTRLS);
1333 1404
1334 /* Copy arguments into temp kernel buffer */ 1405 /* Copy arguments into temp kernel buffer */
1335 switch (_IOC_DIR(cmd)) { 1406 switch (_IOC_DIR(cmd)) {
@@ -1356,13 +1427,43 @@ int video_ioctl2 (struct inode *inode, struct file *file,
1356 break; 1427 break;
1357 } 1428 }
1358 1429
1430 if (is_ext_ctrl) {
1431 struct v4l2_ext_controls *p = parg;
1432
1433 /* In case of an error, tell the caller that it wasn't
1434 a specific control that caused it. */
1435 p->error_idx = p->count;
1436 user_ptr = (void __user *)p->controls;
1437 if (p->count) {
1438 ctrls_size = sizeof(struct v4l2_ext_control) * p->count;
1439 /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */
1440 mbuf = kmalloc(ctrls_size, GFP_KERNEL);
1441 err = -ENOMEM;
1442 if (NULL == mbuf)
1443 goto out_ext_ctrl;
1444 err = -EFAULT;
1445 if (copy_from_user(mbuf, user_ptr, ctrls_size))
1446 goto out_ext_ctrl;
1447 p->controls = mbuf;
1448 }
1449 }
1450
1359 /* Handles IOCTL */ 1451 /* Handles IOCTL */
1360 err = __video_do_ioctl(inode, file, cmd, parg); 1452 err = __video_do_ioctl(inode, file, cmd, parg);
1361 if (err == -ENOIOCTLCMD) 1453 if (err == -ENOIOCTLCMD)
1362 err = -EINVAL; 1454 err = -EINVAL;
1455 if (is_ext_ctrl) {
1456 struct v4l2_ext_controls *p = parg;
1457
1458 p->controls = (void *)user_ptr;
1459 if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size))
1460 err = -EFAULT;
1461 goto out_ext_ctrl;
1462 }
1363 if (err < 0) 1463 if (err < 0)
1364 goto out; 1464 goto out;
1365 1465
1466out_ext_ctrl:
1366 /* Copy results into user buffer */ 1467 /* Copy results into user buffer */
1367 switch (_IOC_DIR(cmd)) 1468 switch (_IOC_DIR(cmd))
1368 { 1469 {
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
index dec6b24e4c42..a1b473190e65 100644
--- a/include/media/v4l2-dev.h
+++ b/include/media/v4l2-dev.h
@@ -232,6 +232,12 @@ struct video_device
232 struct v4l2_control *a); 232 struct v4l2_control *a);
233 int (*vidioc_s_ctrl) (struct file *file, void *fh, 233 int (*vidioc_s_ctrl) (struct file *file, void *fh,
234 struct v4l2_control *a); 234 struct v4l2_control *a);
235 int (*vidioc_g_ext_ctrls) (struct file *file, void *fh,
236 struct v4l2_ext_controls *a);
237 int (*vidioc_s_ext_ctrls) (struct file *file, void *fh,
238 struct v4l2_ext_controls *a);
239 int (*vidioc_try_ext_ctrls) (struct file *file, void *fh,
240 struct v4l2_ext_controls *a);
235 int (*vidioc_querymenu) (struct file *file, void *fh, 241 int (*vidioc_querymenu) (struct file *file, void *fh,
236 struct v4l2_querymenu *a); 242 struct v4l2_querymenu *a);
237 243