aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Verkuil <hans.verkuil@cisco.com>2014-04-27 02:26:30 -0400
committerMauro Carvalho Chehab <m.chehab@samsung.com>2014-07-17 10:56:48 -0400
commit000e4f9a5bcf86fb52914c445ce5634b65e910a2 (patch)
tree88e6df0acadda540020be1d364fcdde2ab8cac91
parent0176077a813933a547b7a913377a87d615b7c108 (diff)
[media] v4l2-ctrls: rewrite copy routines to operate on union v4l2_ctrl_ptr
In order to implement array support and (for the future) configuration stores we need to have more generic copy routines that all operate on the v4l2_ctrl_ptr union. So instead of e.g. using ctrl->cur.string it uses ptr.p_char. This makes e.g. cur_to_user generic so it can be used to copy any v4l2_ctrl_ptr value to userspace, not just the (hardcoded) current value. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls.c129
1 files changed, 56 insertions, 73 deletions
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 09e2c3a2c5c2..e7e0beab7048 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1304,48 +1304,64 @@ static const struct v4l2_ctrl_type_ops std_type_ops = {
1304 .validate = std_validate, 1304 .validate = std_validate,
1305}; 1305};
1306 1306
1307/* Helper function: copy the current control value back to the caller */ 1307/* Helper function: copy the given control value back to the caller */
1308static int cur_to_user(struct v4l2_ext_control *c, 1308static int ptr_to_user(struct v4l2_ext_control *c,
1309 struct v4l2_ctrl *ctrl) 1309 struct v4l2_ctrl *ctrl,
1310 union v4l2_ctrl_ptr ptr)
1310{ 1311{
1311 u32 len; 1312 u32 len;
1312 1313
1313 if (ctrl->is_ptr && !ctrl->is_string) 1314 if (ctrl->is_ptr && !ctrl->is_string)
1314 return copy_to_user(c->ptr, ctrl->cur.p, ctrl->elem_size); 1315 return copy_to_user(c->ptr, ptr.p, ctrl->elem_size);
1315 1316
1316 switch (ctrl->type) { 1317 switch (ctrl->type) {
1317 case V4L2_CTRL_TYPE_STRING: 1318 case V4L2_CTRL_TYPE_STRING:
1318 len = strlen(ctrl->cur.string); 1319 len = strlen(ptr.p_char);
1319 if (c->size < len + 1) { 1320 if (c->size < len + 1) {
1320 c->size = len + 1; 1321 c->size = len + 1;
1321 return -ENOSPC; 1322 return -ENOSPC;
1322 } 1323 }
1323 return copy_to_user(c->string, ctrl->cur.string, 1324 return copy_to_user(c->string, ptr.p_char, len + 1) ?
1324 len + 1) ? -EFAULT : 0; 1325 -EFAULT : 0;
1325 case V4L2_CTRL_TYPE_INTEGER64: 1326 case V4L2_CTRL_TYPE_INTEGER64:
1326 c->value64 = ctrl->cur.val64; 1327 c->value64 = *ptr.p_s64;
1327 break; 1328 break;
1328 default: 1329 default:
1329 c->value = ctrl->cur.val; 1330 c->value = *ptr.p_s32;
1330 break; 1331 break;
1331 } 1332 }
1332 return 0; 1333 return 0;
1333} 1334}
1334 1335
1335/* Helper function: copy the caller-provider value as the new control value */ 1336/* Helper function: copy the current control value back to the caller */
1336static int user_to_new(struct v4l2_ext_control *c, 1337static int cur_to_user(struct v4l2_ext_control *c,
1337 struct v4l2_ctrl *ctrl) 1338 struct v4l2_ctrl *ctrl)
1338{ 1339{
1340 return ptr_to_user(c, ctrl, ctrl->p_cur);
1341}
1342
1343/* Helper function: copy the new control value back to the caller */
1344static int new_to_user(struct v4l2_ext_control *c,
1345 struct v4l2_ctrl *ctrl)
1346{
1347 return ptr_to_user(c, ctrl, ctrl->p_new);
1348}
1349
1350/* Helper function: copy the caller-provider value to the given control value */
1351static int user_to_ptr(struct v4l2_ext_control *c,
1352 struct v4l2_ctrl *ctrl,
1353 union v4l2_ctrl_ptr ptr)
1354{
1339 int ret; 1355 int ret;
1340 u32 size; 1356 u32 size;
1341 1357
1342 ctrl->is_new = 1; 1358 ctrl->is_new = 1;
1343 if (ctrl->is_ptr && !ctrl->is_string) 1359 if (ctrl->is_ptr && !ctrl->is_string)
1344 return copy_from_user(ctrl->p, c->ptr, ctrl->elem_size); 1360 return copy_from_user(ptr.p, c->ptr, ctrl->elem_size);
1345 1361
1346 switch (ctrl->type) { 1362 switch (ctrl->type) {
1347 case V4L2_CTRL_TYPE_INTEGER64: 1363 case V4L2_CTRL_TYPE_INTEGER64:
1348 ctrl->val64 = c->value64; 1364 *ptr.p_s64 = c->value64;
1349 break; 1365 break;
1350 case V4L2_CTRL_TYPE_STRING: 1366 case V4L2_CTRL_TYPE_STRING:
1351 size = c->size; 1367 size = c->size;
@@ -1353,83 +1369,64 @@ static int user_to_new(struct v4l2_ext_control *c,
1353 return -ERANGE; 1369 return -ERANGE;
1354 if (size > ctrl->maximum + 1) 1370 if (size > ctrl->maximum + 1)
1355 size = ctrl->maximum + 1; 1371 size = ctrl->maximum + 1;
1356 ret = copy_from_user(ctrl->string, c->string, size); 1372 ret = copy_from_user(ptr.p_char, c->string, size);
1357 if (!ret) { 1373 if (!ret) {
1358 char last = ctrl->string[size - 1]; 1374 char last = ptr.p_char[size - 1];
1359 1375
1360 ctrl->string[size - 1] = 0; 1376 ptr.p_char[size - 1] = 0;
1361 /* If the string was longer than ctrl->maximum, 1377 /* If the string was longer than ctrl->maximum,
1362 then return an error. */ 1378 then return an error. */
1363 if (strlen(ctrl->string) == ctrl->maximum && last) 1379 if (strlen(ptr.p_char) == ctrl->maximum && last)
1364 return -ERANGE; 1380 return -ERANGE;
1365 } 1381 }
1366 return ret ? -EFAULT : 0; 1382 return ret ? -EFAULT : 0;
1367 default: 1383 default:
1368 ctrl->val = c->value; 1384 *ptr.p_s32 = c->value;
1369 break; 1385 break;
1370 } 1386 }
1371 return 0; 1387 return 0;
1372} 1388}
1373 1389
1374/* Helper function: copy the new control value back to the caller */ 1390/* Helper function: copy the caller-provider value as the new control value */
1375static int new_to_user(struct v4l2_ext_control *c, 1391static int user_to_new(struct v4l2_ext_control *c,
1376 struct v4l2_ctrl *ctrl) 1392 struct v4l2_ctrl *ctrl)
1377{ 1393{
1378 u32 len; 1394 return user_to_ptr(c, ctrl, ctrl->p_new);
1379 1395}
1380 if (ctrl->is_ptr && !ctrl->is_string)
1381 return copy_to_user(c->ptr, ctrl->p, ctrl->elem_size);
1382 1396
1397/* Copy the one value to another. */
1398static void ptr_to_ptr(struct v4l2_ctrl *ctrl,
1399 union v4l2_ctrl_ptr from, union v4l2_ctrl_ptr to)
1400{
1401 if (ctrl == NULL)
1402 return;
1383 switch (ctrl->type) { 1403 switch (ctrl->type) {
1384 case V4L2_CTRL_TYPE_STRING: 1404 case V4L2_CTRL_TYPE_STRING:
1385 len = strlen(ctrl->string); 1405 /* strings are always 0-terminated */
1386 if (c->size < len + 1) { 1406 strcpy(to.p_char, from.p_char);
1387 c->size = ctrl->maximum + 1; 1407 break;
1388 return -ENOSPC;
1389 }
1390 return copy_to_user(c->string, ctrl->string,
1391 len + 1) ? -EFAULT : 0;
1392 case V4L2_CTRL_TYPE_INTEGER64: 1408 case V4L2_CTRL_TYPE_INTEGER64:
1393 c->value64 = ctrl->val64; 1409 *to.p_s64 = *from.p_s64;
1394 break; 1410 break;
1395 default: 1411 default:
1396 c->value = ctrl->val; 1412 if (ctrl->is_ptr)
1413 memcpy(to.p, from.p, ctrl->elem_size);
1414 else
1415 *to.p_s32 = *from.p_s32;
1397 break; 1416 break;
1398 } 1417 }
1399 return 0;
1400} 1418}
1401 1419
1402/* Copy the new value to the current value. */ 1420/* Copy the new value to the current value. */
1403static void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags) 1421static void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags)
1404{ 1422{
1405 bool changed = false; 1423 bool changed;
1406 1424
1407 if (ctrl == NULL) 1425 if (ctrl == NULL)
1408 return; 1426 return;
1427 changed = !ctrl->type_ops->equal(ctrl, ctrl->p_cur, ctrl->p_new);
1428 ptr_to_ptr(ctrl, ctrl->p_new, ctrl->p_cur);
1409 1429
1410 switch (ctrl->type) {
1411 case V4L2_CTRL_TYPE_BUTTON:
1412 changed = true;
1413 break;
1414 case V4L2_CTRL_TYPE_STRING:
1415 /* strings are always 0-terminated */
1416 changed = strcmp(ctrl->string, ctrl->cur.string);
1417 strcpy(ctrl->cur.string, ctrl->string);
1418 break;
1419 case V4L2_CTRL_TYPE_INTEGER64:
1420 changed = ctrl->val64 != ctrl->cur.val64;
1421 ctrl->cur.val64 = ctrl->val64;
1422 break;
1423 default:
1424 if (ctrl->is_ptr) {
1425 changed = memcmp(ctrl->p, ctrl->cur.p, ctrl->elem_size);
1426 memcpy(ctrl->cur.p, ctrl->p, ctrl->elem_size);
1427 } else {
1428 changed = ctrl->val != ctrl->cur.val;
1429 ctrl->cur.val = ctrl->val;
1430 }
1431 break;
1432 }
1433 if (ch_flags & V4L2_EVENT_CTRL_CH_FLAGS) { 1430 if (ch_flags & V4L2_EVENT_CTRL_CH_FLAGS) {
1434 /* Note: CH_FLAGS is only set for auto clusters. */ 1431 /* Note: CH_FLAGS is only set for auto clusters. */
1435 ctrl->flags &= 1432 ctrl->flags &=
@@ -1458,21 +1455,7 @@ static void cur_to_new(struct v4l2_ctrl *ctrl)
1458{ 1455{
1459 if (ctrl == NULL) 1456 if (ctrl == NULL)
1460 return; 1457 return;
1461 switch (ctrl->type) { 1458 ptr_to_ptr(ctrl, ctrl->p_cur, ctrl->p_new);
1462 case V4L2_CTRL_TYPE_STRING:
1463 /* strings are always 0-terminated */
1464 strcpy(ctrl->string, ctrl->cur.string);
1465 break;
1466 case V4L2_CTRL_TYPE_INTEGER64:
1467 ctrl->val64 = ctrl->cur.val64;
1468 break;
1469 default:
1470 if (ctrl->is_ptr)
1471 memcpy(ctrl->p, ctrl->cur.p, ctrl->elem_size);
1472 else
1473 ctrl->val = ctrl->cur.val;
1474 break;
1475 }
1476} 1459}
1477 1460
1478/* Return non-zero if one or more of the controls in the cluster has a new 1461/* Return non-zero if one or more of the controls in the cluster has a new