diff options
author | Hans Verkuil <hans.verkuil@cisco.com> | 2014-04-27 02:26:30 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <m.chehab@samsung.com> | 2014-07-17 10:56:48 -0400 |
commit | 000e4f9a5bcf86fb52914c445ce5634b65e910a2 (patch) | |
tree | 88e6df0acadda540020be1d364fcdde2ab8cac91 | |
parent | 0176077a813933a547b7a913377a87d615b7c108 (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.c | 129 |
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 */ |
1308 | static int cur_to_user(struct v4l2_ext_control *c, | 1308 | static 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 */ |
1336 | static int user_to_new(struct v4l2_ext_control *c, | 1337 | static 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 */ | ||
1344 | static 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 */ | ||
1351 | static 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 */ |
1375 | static int new_to_user(struct v4l2_ext_control *c, | 1391 | static 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. */ | ||
1398 | static 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. */ |
1403 | static void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags) | 1421 | static 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 |