aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2010-06-18 10:31:24 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-08-02 14:34:10 -0400
commitb30ece53946ad2b79304ee5cfdb18b361dc3a3fc (patch)
tree80dc24b56b1a38d03d50e8077ae275ec02391847
parent1b4e21c4f62eae6bdcb3e7bfdfc52171a24f3689 (diff)
V4L/DVB: uvcvideo: Don't use stack-based buffers for USB transfers
Data buffers on the stack are not allowed for USB I/O. Use dynamically allocated buffers instead when querying control length and control capabilities. The control capabilities are now also stored in the uvc_control structure. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/video/uvc/uvc_ctrl.c51
-rw-r--r--drivers/media/video/uvc/uvc_v4l2.c3
-rw-r--r--drivers/media/video/uvc/uvcvideo.h3
3 files changed, 38 insertions, 19 deletions
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
index fa06cf512ecf..a350fad0db43 100644
--- a/drivers/media/video/uvc/uvc_ctrl.c
+++ b/drivers/media/video/uvc/uvc_ctrl.c
@@ -643,7 +643,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
643 643
644static inline __u8 *uvc_ctrl_data(struct uvc_control *ctrl, int id) 644static inline __u8 *uvc_ctrl_data(struct uvc_control *ctrl, int id)
645{ 645{
646 return ctrl->data + id * ctrl->info->size; 646 return ctrl->uvc_data + id * ctrl->info->size;
647} 647}
648 648
649static inline int uvc_test_bit(const __u8 *data, int bit) 649static inline int uvc_test_bit(const __u8 *data, int bit)
@@ -1293,13 +1293,15 @@ int uvc_ctrl_resume_device(struct uvc_device *dev)
1293 * Control and mapping handling 1293 * Control and mapping handling
1294 */ 1294 */
1295 1295
1296static void uvc_ctrl_add_ctrl(struct uvc_device *dev, 1296static int uvc_ctrl_add_ctrl(struct uvc_device *dev,
1297 struct uvc_control_info *info) 1297 struct uvc_control_info *info)
1298{ 1298{
1299 struct uvc_entity *entity; 1299 struct uvc_entity *entity;
1300 struct uvc_control *ctrl = NULL; 1300 struct uvc_control *ctrl = NULL;
1301 int ret, found = 0; 1301 int ret = 0, found = 0;
1302 unsigned int i; 1302 unsigned int i;
1303 u8 *uvc_info;
1304 u8 *uvc_data;
1303 1305
1304 list_for_each_entry(entity, &dev->entities, list) { 1306 list_for_each_entry(entity, &dev->entities, list) {
1305 if (!uvc_entity_match_guid(entity, info->entity)) 1307 if (!uvc_entity_match_guid(entity, info->entity))
@@ -1318,56 +1320,69 @@ static void uvc_ctrl_add_ctrl(struct uvc_device *dev,
1318 } 1320 }
1319 1321
1320 if (!found) 1322 if (!found)
1321 return; 1323 return 0;
1324
1325 uvc_data = kmalloc(info->size * UVC_CTRL_DATA_LAST + 1, GFP_KERNEL);
1326 if (uvc_data == NULL)
1327 return -ENOMEM;
1328
1329 uvc_info = uvc_data + info->size * UVC_CTRL_DATA_LAST;
1322 1330
1323 if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT) { 1331 if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT) {
1324 /* Check if the device control information and length match 1332 /* Check if the device control information and length match
1325 * the user supplied information. 1333 * the user supplied information.
1326 */ 1334 */
1327 __le16 size;
1328 __u8 _info;
1329
1330 ret = uvc_query_ctrl(dev, UVC_GET_LEN, ctrl->entity->id, 1335 ret = uvc_query_ctrl(dev, UVC_GET_LEN, ctrl->entity->id,
1331 dev->intfnum, info->selector, (__u8 *)&size, 2); 1336 dev->intfnum, info->selector, uvc_data, 2);
1332 if (ret < 0) { 1337 if (ret < 0) {
1333 uvc_trace(UVC_TRACE_CONTROL, 1338 uvc_trace(UVC_TRACE_CONTROL,
1334 "GET_LEN failed on control %pUl/%u (%d).\n", 1339 "GET_LEN failed on control %pUl/%u (%d).\n",
1335 info->entity, info->selector, ret); 1340 info->entity, info->selector, ret);
1336 return; 1341 goto done;
1337 } 1342 }
1338 1343
1339 if (info->size != le16_to_cpu(size)) { 1344 if (info->size != le16_to_cpu(*(__le16 *)uvc_data)) {
1340 uvc_trace(UVC_TRACE_CONTROL, "Control %pUl/%u size " 1345 uvc_trace(UVC_TRACE_CONTROL, "Control %pUl/%u size "
1341 "doesn't match user supplied value.\n", 1346 "doesn't match user supplied value.\n",
1342 info->entity, info->selector); 1347 info->entity, info->selector);
1343 return; 1348 ret = -EINVAL;
1349 goto done;
1344 } 1350 }
1345 1351
1346 ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id, 1352 ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id,
1347 dev->intfnum, info->selector, &_info, 1); 1353 dev->intfnum, info->selector, uvc_info, 1);
1348 if (ret < 0) { 1354 if (ret < 0) {
1349 uvc_trace(UVC_TRACE_CONTROL, 1355 uvc_trace(UVC_TRACE_CONTROL,
1350 "GET_INFO failed on control %pUl/%u (%d).\n", 1356 "GET_INFO failed on control %pUl/%u (%d).\n",
1351 info->entity, info->selector, ret); 1357 info->entity, info->selector, ret);
1352 return; 1358 goto done;
1353 } 1359 }
1354 1360
1355 if (((info->flags & UVC_CONTROL_GET_CUR) && 1361 if (((info->flags & UVC_CONTROL_GET_CUR) &&
1356 !(_info & UVC_CONTROL_CAP_GET)) || 1362 !(*uvc_info & UVC_CONTROL_CAP_GET)) ||
1357 ((info->flags & UVC_CONTROL_SET_CUR) && 1363 ((info->flags & UVC_CONTROL_SET_CUR) &&
1358 !(_info & UVC_CONTROL_CAP_SET))) { 1364 !(*uvc_info & UVC_CONTROL_CAP_SET))) {
1359 uvc_trace(UVC_TRACE_CONTROL, "Control %pUl/%u flags " 1365 uvc_trace(UVC_TRACE_CONTROL, "Control %pUl/%u flags "
1360 "don't match supported operations.\n", 1366 "don't match supported operations.\n",
1361 info->entity, info->selector); 1367 info->entity, info->selector);
1362 return; 1368 ret = -EINVAL;
1369 goto done;
1363 } 1370 }
1364 } 1371 }
1365 1372
1366 ctrl->info = info; 1373 ctrl->info = info;
1367 ctrl->data = kmalloc(ctrl->info->size * UVC_CTRL_DATA_LAST, GFP_KERNEL); 1374 ctrl->uvc_data = uvc_data;
1375 ctrl->uvc_info = uvc_info;
1376
1368 uvc_trace(UVC_TRACE_CONTROL, "Added control %pUl/%u to device %s " 1377 uvc_trace(UVC_TRACE_CONTROL, "Added control %pUl/%u to device %s "
1369 "entity %u\n", ctrl->info->entity, ctrl->info->selector, 1378 "entity %u\n", ctrl->info->entity, ctrl->info->selector,
1370 dev->udev->devpath, entity->id); 1379 dev->udev->devpath, entity->id);
1380
1381done:
1382 if (ret < 0)
1383 kfree(uvc_data);
1384
1385 return ret;
1371} 1386}
1372 1387
1373/* 1388/*
@@ -1600,7 +1615,7 @@ void uvc_ctrl_cleanup_device(struct uvc_device *dev)
1600 1615
1601 list_for_each_entry(entity, &dev->entities, list) { 1616 list_for_each_entry(entity, &dev->entities, list) {
1602 for (i = 0; i < entity->ncontrols; ++i) 1617 for (i = 0; i < entity->ncontrols; ++i)
1603 kfree(entity->controls[i].data); 1618 kfree(entity->controls[i].uvc_data);
1604 1619
1605 kfree(entity->controls); 1620 kfree(entity->controls);
1606 } 1621 }
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
index 485a89912cef..369ce06be035 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -1028,6 +1028,9 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
1028 if (!capable(CAP_SYS_ADMIN)) 1028 if (!capable(CAP_SYS_ADMIN))
1029 return -EPERM; 1029 return -EPERM;
1030 1030
1031 if (xinfo->size == 0)
1032 return -EINVAL;
1033
1031 info = kzalloc(sizeof *info, GFP_KERNEL); 1034 info = kzalloc(sizeof *info, GFP_KERNEL);
1032 if (info == NULL) 1035 if (info == NULL)
1033 return -ENOMEM; 1036 return -ENOMEM;
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index 14f77e42fd45..47b20e7e3786 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -262,7 +262,8 @@ struct uvc_control {
262 modified : 1, 262 modified : 1,
263 cached : 1; 263 cached : 1;
264 264
265 __u8 *data; 265 __u8 *uvc_data;
266 __u8 *uvc_info;
266}; 267};
267 268
268struct uvc_format_desc { 269struct uvc_format_desc {