aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/uvc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/uvc')
-rw-r--r--drivers/media/video/uvc/uvc_ctrl.c130
-rw-r--r--drivers/media/video/uvc/uvcvideo.h11
2 files changed, 68 insertions, 73 deletions
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
index 531a3e1a6d1..97a2395671b 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->uvc_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)
@@ -766,10 +766,10 @@ static void __uvc_find_control(struct uvc_entity *entity, __u32 v4l2_id,
766 766
767 for (i = 0; i < entity->ncontrols; ++i) { 767 for (i = 0; i < entity->ncontrols; ++i) {
768 ctrl = &entity->controls[i]; 768 ctrl = &entity->controls[i];
769 if (ctrl->info == NULL) 769 if (!ctrl->initialized)
770 continue; 770 continue;
771 771
772 list_for_each_entry(map, &ctrl->info->mappings, list) { 772 list_for_each_entry(map, &ctrl->info.mappings, list) {
773 if ((map->id == v4l2_id) && !next) { 773 if ((map->id == v4l2_id) && !next) {
774 *control = ctrl; 774 *control = ctrl;
775 *mapping = map; 775 *mapping = map;
@@ -816,36 +816,36 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain,
816{ 816{
817 int ret; 817 int ret;
818 818
819 if (ctrl->info->flags & UVC_CONTROL_GET_DEF) { 819 if (ctrl->info.flags & UVC_CONTROL_GET_DEF) {
820 ret = uvc_query_ctrl(chain->dev, UVC_GET_DEF, ctrl->entity->id, 820 ret = uvc_query_ctrl(chain->dev, UVC_GET_DEF, ctrl->entity->id,
821 chain->dev->intfnum, ctrl->info->selector, 821 chain->dev->intfnum, ctrl->info.selector,
822 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF), 822 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF),
823 ctrl->info->size); 823 ctrl->info.size);
824 if (ret < 0) 824 if (ret < 0)
825 return ret; 825 return ret;
826 } 826 }
827 827
828 if (ctrl->info->flags & UVC_CONTROL_GET_MIN) { 828 if (ctrl->info.flags & UVC_CONTROL_GET_MIN) {
829 ret = uvc_query_ctrl(chain->dev, UVC_GET_MIN, ctrl->entity->id, 829 ret = uvc_query_ctrl(chain->dev, UVC_GET_MIN, ctrl->entity->id,
830 chain->dev->intfnum, ctrl->info->selector, 830 chain->dev->intfnum, ctrl->info.selector,
831 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN), 831 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN),
832 ctrl->info->size); 832 ctrl->info.size);
833 if (ret < 0) 833 if (ret < 0)
834 return ret; 834 return ret;
835 } 835 }
836 if (ctrl->info->flags & UVC_CONTROL_GET_MAX) { 836 if (ctrl->info.flags & UVC_CONTROL_GET_MAX) {
837 ret = uvc_query_ctrl(chain->dev, UVC_GET_MAX, ctrl->entity->id, 837 ret = uvc_query_ctrl(chain->dev, UVC_GET_MAX, ctrl->entity->id,
838 chain->dev->intfnum, ctrl->info->selector, 838 chain->dev->intfnum, ctrl->info.selector,
839 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX), 839 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX),
840 ctrl->info->size); 840 ctrl->info.size);
841 if (ret < 0) 841 if (ret < 0)
842 return ret; 842 return ret;
843 } 843 }
844 if (ctrl->info->flags & UVC_CONTROL_GET_RES) { 844 if (ctrl->info.flags & UVC_CONTROL_GET_RES) {
845 ret = uvc_query_ctrl(chain->dev, UVC_GET_RES, ctrl->entity->id, 845 ret = uvc_query_ctrl(chain->dev, UVC_GET_RES, ctrl->entity->id,
846 chain->dev->intfnum, ctrl->info->selector, 846 chain->dev->intfnum, ctrl->info.selector,
847 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES), 847 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES),
848 ctrl->info->size); 848 ctrl->info.size);
849 if (ret < 0) 849 if (ret < 0)
850 return ret; 850 return ret;
851 } 851 }
@@ -873,9 +873,9 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
873 strlcpy(v4l2_ctrl->name, mapping->name, sizeof v4l2_ctrl->name); 873 strlcpy(v4l2_ctrl->name, mapping->name, sizeof v4l2_ctrl->name);
874 v4l2_ctrl->flags = 0; 874 v4l2_ctrl->flags = 0;
875 875
876 if (!(ctrl->info->flags & UVC_CONTROL_GET_CUR)) 876 if (!(ctrl->info.flags & UVC_CONTROL_GET_CUR))
877 v4l2_ctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY; 877 v4l2_ctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
878 if (!(ctrl->info->flags & UVC_CONTROL_SET_CUR)) 878 if (!(ctrl->info.flags & UVC_CONTROL_SET_CUR))
879 v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; 879 v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
880 880
881 if (!ctrl->cached) { 881 if (!ctrl->cached) {
@@ -884,7 +884,7 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
884 return ret; 884 return ret;
885 } 885 }
886 886
887 if (ctrl->info->flags & UVC_CONTROL_GET_DEF) { 887 if (ctrl->info.flags & UVC_CONTROL_GET_DEF) {
888 v4l2_ctrl->default_value = mapping->get(mapping, UVC_GET_DEF, 888 v4l2_ctrl->default_value = mapping->get(mapping, UVC_GET_DEF,
889 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF)); 889 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
890 } 890 }
@@ -921,15 +921,15 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
921 break; 921 break;
922 } 922 }
923 923
924 if (ctrl->info->flags & UVC_CONTROL_GET_MIN) 924 if (ctrl->info.flags & UVC_CONTROL_GET_MIN)
925 v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN, 925 v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN,
926 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN)); 926 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
927 927
928 if (ctrl->info->flags & UVC_CONTROL_GET_MAX) 928 if (ctrl->info.flags & UVC_CONTROL_GET_MAX)
929 v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX, 929 v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX,
930 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX)); 930 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
931 931
932 if (ctrl->info->flags & UVC_CONTROL_GET_RES) 932 if (ctrl->info.flags & UVC_CONTROL_GET_RES)
933 v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES, 933 v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES,
934 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES)); 934 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
935 935
@@ -978,14 +978,14 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
978 978
979 for (i = 0; i < entity->ncontrols; ++i) { 979 for (i = 0; i < entity->ncontrols; ++i) {
980 ctrl = &entity->controls[i]; 980 ctrl = &entity->controls[i];
981 if (ctrl->info == NULL) 981 if (!ctrl->initialized)
982 continue; 982 continue;
983 983
984 /* Reset the loaded flag for auto-update controls that were 984 /* Reset the loaded flag for auto-update controls that were
985 * marked as loaded in uvc_ctrl_get/uvc_ctrl_set to prevent 985 * marked as loaded in uvc_ctrl_get/uvc_ctrl_set to prevent
986 * uvc_ctrl_get from using the cached value. 986 * uvc_ctrl_get from using the cached value.
987 */ 987 */
988 if (ctrl->info->flags & UVC_CONTROL_AUTO_UPDATE) 988 if (ctrl->info.flags & UVC_CONTROL_AUTO_UPDATE)
989 ctrl->loaded = 0; 989 ctrl->loaded = 0;
990 990
991 if (!ctrl->dirty) 991 if (!ctrl->dirty)
@@ -993,16 +993,16 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
993 993
994 if (!rollback) 994 if (!rollback)
995 ret = uvc_query_ctrl(dev, UVC_SET_CUR, ctrl->entity->id, 995 ret = uvc_query_ctrl(dev, UVC_SET_CUR, ctrl->entity->id,
996 dev->intfnum, ctrl->info->selector, 996 dev->intfnum, ctrl->info.selector,
997 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), 997 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
998 ctrl->info->size); 998 ctrl->info.size);
999 else 999 else
1000 ret = 0; 1000 ret = 0;
1001 1001
1002 if (rollback || ret < 0) 1002 if (rollback || ret < 0)
1003 memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), 1003 memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
1004 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP), 1004 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
1005 ctrl->info->size); 1005 ctrl->info.size);
1006 1006
1007 ctrl->dirty = 0; 1007 ctrl->dirty = 0;
1008 1008
@@ -1040,14 +1040,14 @@ int uvc_ctrl_get(struct uvc_video_chain *chain,
1040 int ret; 1040 int ret;
1041 1041
1042 ctrl = uvc_find_control(chain, xctrl->id, &mapping); 1042 ctrl = uvc_find_control(chain, xctrl->id, &mapping);
1043 if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0) 1043 if (ctrl == NULL || (ctrl->info.flags & UVC_CONTROL_GET_CUR) == 0)
1044 return -EINVAL; 1044 return -EINVAL;
1045 1045
1046 if (!ctrl->loaded) { 1046 if (!ctrl->loaded) {
1047 ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, ctrl->entity->id, 1047 ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, ctrl->entity->id,
1048 chain->dev->intfnum, ctrl->info->selector, 1048 chain->dev->intfnum, ctrl->info.selector,
1049 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), 1049 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
1050 ctrl->info->size); 1050 ctrl->info.size);
1051 if (ret < 0) 1051 if (ret < 0)
1052 return ret; 1052 return ret;
1053 1053
@@ -1082,7 +1082,7 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
1082 int ret; 1082 int ret;
1083 1083
1084 ctrl = uvc_find_control(chain, xctrl->id, &mapping); 1084 ctrl = uvc_find_control(chain, xctrl->id, &mapping);
1085 if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_SET_CUR) == 0) 1085 if (ctrl == NULL || (ctrl->info.flags & UVC_CONTROL_SET_CUR) == 0)
1086 return -EINVAL; 1086 return -EINVAL;
1087 1087
1088 /* Clamp out of range values. */ 1088 /* Clamp out of range values. */
@@ -1128,16 +1128,16 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
1128 * needs to be loaded from the device to perform the read-modify-write 1128 * needs to be loaded from the device to perform the read-modify-write
1129 * operation. 1129 * operation.
1130 */ 1130 */
1131 if (!ctrl->loaded && (ctrl->info->size * 8) != mapping->size) { 1131 if (!ctrl->loaded && (ctrl->info.size * 8) != mapping->size) {
1132 if ((ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0) { 1132 if ((ctrl->info.flags & UVC_CONTROL_GET_CUR) == 0) {
1133 memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), 1133 memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
1134 0, ctrl->info->size); 1134 0, ctrl->info.size);
1135 } else { 1135 } else {
1136 ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, 1136 ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR,
1137 ctrl->entity->id, chain->dev->intfnum, 1137 ctrl->entity->id, chain->dev->intfnum,
1138 ctrl->info->selector, 1138 ctrl->info.selector,
1139 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), 1139 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
1140 ctrl->info->size); 1140 ctrl->info.size);
1141 if (ret < 0) 1141 if (ret < 0)
1142 return ret; 1142 return ret;
1143 } 1143 }
@@ -1149,7 +1149,7 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
1149 if (!ctrl->dirty) { 1149 if (!ctrl->dirty) {
1150 memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP), 1150 memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
1151 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), 1151 uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
1152 ctrl->info->size); 1152 ctrl->info.size);
1153 } 1153 }
1154 1154
1155 mapping->set(mapping, value, 1155 mapping->set(mapping, value,
@@ -1189,10 +1189,10 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
1189 /* Find the control. */ 1189 /* Find the control. */
1190 for (i = 0; i < entity->ncontrols; ++i) { 1190 for (i = 0; i < entity->ncontrols; ++i) {
1191 ctrl = &entity->controls[i]; 1191 ctrl = &entity->controls[i];
1192 if (ctrl->info == NULL) 1192 if (!ctrl->initialized)
1193 continue; 1193 continue;
1194 1194
1195 if (ctrl->info->selector == xctrl->selector) { 1195 if (ctrl->info.selector == xctrl->selector) {
1196 found = 1; 1196 found = 1;
1197 break; 1197 break;
1198 } 1198 }
@@ -1205,11 +1205,11 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
1205 } 1205 }
1206 1206
1207 /* Validate control data size. */ 1207 /* Validate control data size. */
1208 if (ctrl->info->size != xctrl->size) 1208 if (ctrl->info.size != xctrl->size)
1209 return -EINVAL; 1209 return -EINVAL;
1210 1210
1211 if ((set && !(ctrl->info->flags & UVC_CONTROL_SET_CUR)) || 1211 if ((set && !(ctrl->info.flags & UVC_CONTROL_SET_CUR)) ||
1212 (!set && !(ctrl->info->flags & UVC_CONTROL_GET_CUR))) 1212 (!set && !(ctrl->info.flags & UVC_CONTROL_GET_CUR)))
1213 return -EINVAL; 1213 return -EINVAL;
1214 1214
1215 if (mutex_lock_interruptible(&chain->ctrl_mutex)) 1215 if (mutex_lock_interruptible(&chain->ctrl_mutex))
@@ -1272,13 +1272,13 @@ int uvc_ctrl_resume_device(struct uvc_device *dev)
1272 for (i = 0; i < entity->ncontrols; ++i) { 1272 for (i = 0; i < entity->ncontrols; ++i) {
1273 ctrl = &entity->controls[i]; 1273 ctrl = &entity->controls[i];
1274 1274
1275 if (ctrl->info == NULL || !ctrl->modified || 1275 if (!ctrl->initialized || !ctrl->modified ||
1276 (ctrl->info->flags & UVC_CONTROL_RESTORE) == 0) 1276 (ctrl->info.flags & UVC_CONTROL_RESTORE) == 0)
1277 continue; 1277 continue;
1278 1278
1279 printk(KERN_INFO "restoring control %pUl/%u/%u\n", 1279 printk(KERN_INFO "restoring control %pUl/%u/%u\n",
1280 ctrl->info->entity, ctrl->info->index, 1280 ctrl->info.entity, ctrl->info.index,
1281 ctrl->info->selector); 1281 ctrl->info.selector);
1282 ctrl->dirty = 1; 1282 ctrl->dirty = 1;
1283 } 1283 }
1284 1284
@@ -1361,31 +1361,26 @@ static int uvc_ctrl_add_info(struct uvc_device *dev, struct uvc_control *ctrl,
1361{ 1361{
1362 int ret = 0; 1362 int ret = 0;
1363 1363
1364 /* Clone the control info struct for this device's instance */ 1364 memcpy(&ctrl->info, info, sizeof(*info));
1365 ctrl->info = kmemdup(info, sizeof(*info), GFP_KERNEL); 1365 INIT_LIST_HEAD(&ctrl->info.mappings);
1366 if (ctrl->info == NULL) {
1367 ret = -ENOMEM;
1368 goto done;
1369 }
1370 INIT_LIST_HEAD(&ctrl->info->mappings);
1371 1366
1372 /* Allocate an array to save control values (cur, def, max, etc.) */ 1367 /* Allocate an array to save control values (cur, def, max, etc.) */
1373 ctrl->uvc_data = kzalloc(ctrl->info->size * UVC_CTRL_DATA_LAST + 1, 1368 ctrl->uvc_data = kzalloc(ctrl->info.size * UVC_CTRL_DATA_LAST + 1,
1374 GFP_KERNEL); 1369 GFP_KERNEL);
1375 if (ctrl->uvc_data == NULL) { 1370 if (ctrl->uvc_data == NULL) {
1376 ret = -ENOMEM; 1371 ret = -ENOMEM;
1377 goto done; 1372 goto done;
1378 } 1373 }
1379 1374
1375 ctrl->initialized = 1;
1376
1380 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 "
1381 "entity %u\n", ctrl->info->entity, ctrl->info->selector, 1378 "entity %u\n", ctrl->info.entity, ctrl->info.selector,
1382 dev->udev->devpath, ctrl->entity->id); 1379 dev->udev->devpath, ctrl->entity->id);
1383 1380
1384done: 1381done:
1385 if (ret < 0) { 1382 if (ret < 0)
1386 kfree(ctrl->uvc_data); 1383 kfree(ctrl->uvc_data);
1387 kfree(ctrl->info);
1388 }
1389 return ret; 1384 return ret;
1390} 1385}
1391 1386
@@ -1418,11 +1413,11 @@ static int __uvc_ctrl_add_mapping(struct uvc_device *dev,
1418 if (map->set == NULL) 1413 if (map->set == NULL)
1419 map->set = uvc_set_le_value; 1414 map->set = uvc_set_le_value;
1420 1415
1421 map->ctrl = ctrl->info; 1416 map->ctrl = &ctrl->info;
1422 list_add_tail(&map->list, &ctrl->info->mappings); 1417 list_add_tail(&map->list, &ctrl->info.mappings);
1423 uvc_trace(UVC_TRACE_CONTROL, 1418 uvc_trace(UVC_TRACE_CONTROL,
1424 "Adding mapping '%s' to control %pUl/%u.\n", 1419 "Adding mapping '%s' to control %pUl/%u.\n",
1425 map->name, ctrl->info->entity, ctrl->info->selector); 1420 map->name, ctrl->info.entity, ctrl->info.selector);
1426 1421
1427 return 0; 1422 return 0;
1428} 1423}
@@ -1453,8 +1448,8 @@ int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
1453 1448
1454 for (i = 0; i < entity->ncontrols; ++i) { 1449 for (i = 0; i < entity->ncontrols; ++i) {
1455 ctrl = &entity->controls[i]; 1450 ctrl = &entity->controls[i];
1456 if (ctrl->info != NULL && 1451 if (ctrl->initialized &&
1457 ctrl->info->selector == mapping->selector) { 1452 ctrl->info.selector == mapping->selector) {
1458 found = 1; 1453 found = 1;
1459 break; 1454 break;
1460 } 1455 }
@@ -1469,7 +1464,7 @@ int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
1469 if (mutex_lock_interruptible(&chain->ctrl_mutex)) 1464 if (mutex_lock_interruptible(&chain->ctrl_mutex))
1470 return -ERESTARTSYS; 1465 return -ERESTARTSYS;
1471 1466
1472 list_for_each_entry(map, &ctrl->info->mappings, list) { 1467 list_for_each_entry(map, &ctrl->info.mappings, list) {
1473 if (mapping->id == map->id) { 1468 if (mapping->id == map->id) {
1474 uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s', " 1469 uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s', "
1475 "control id 0x%08x already exists.\n", 1470 "control id 0x%08x already exists.\n",
@@ -1601,12 +1596,12 @@ static void uvc_ctrl_init_ctrl(struct uvc_device *dev, struct uvc_control *ctrl)
1601 } 1596 }
1602 } 1597 }
1603 1598
1604 if (ctrl->info == NULL) 1599 if (!ctrl->initialized)
1605 return; 1600 return;
1606 1601
1607 for (; mapping < mend; ++mapping) { 1602 for (; mapping < mend; ++mapping) {
1608 if (uvc_entity_match_guid(ctrl->entity, mapping->entity) && 1603 if (uvc_entity_match_guid(ctrl->entity, mapping->entity) &&
1609 ctrl->info->selector == mapping->selector) 1604 ctrl->info.selector == mapping->selector)
1610 __uvc_ctrl_add_mapping(dev, ctrl, mapping); 1605 __uvc_ctrl_add_mapping(dev, ctrl, mapping);
1611 } 1606 }
1612} 1607}
@@ -1676,7 +1671,7 @@ static void uvc_ctrl_cleanup_mappings(struct uvc_device *dev,
1676{ 1671{
1677 struct uvc_control_mapping *mapping, *nm; 1672 struct uvc_control_mapping *mapping, *nm;
1678 1673
1679 list_for_each_entry_safe(mapping, nm, &ctrl->info->mappings, list) { 1674 list_for_each_entry_safe(mapping, nm, &ctrl->info.mappings, list) {
1680 list_del(&mapping->list); 1675 list_del(&mapping->list);
1681 kfree(mapping->menu_info); 1676 kfree(mapping->menu_info);
1682 kfree(mapping); 1677 kfree(mapping);
@@ -1693,12 +1688,11 @@ void uvc_ctrl_cleanup_device(struct uvc_device *dev)
1693 for (i = 0; i < entity->ncontrols; ++i) { 1688 for (i = 0; i < entity->ncontrols; ++i) {
1694 struct uvc_control *ctrl = &entity->controls[i]; 1689 struct uvc_control *ctrl = &entity->controls[i];
1695 1690
1696 if (ctrl->info == NULL) 1691 if (!ctrl->initialized)
1697 continue; 1692 continue;
1698 1693
1699 uvc_ctrl_cleanup_mappings(dev, ctrl); 1694 uvc_ctrl_cleanup_mappings(dev, ctrl);
1700 kfree(ctrl->uvc_data); 1695 kfree(ctrl->uvc_data);
1701 kfree(ctrl->info);
1702 } 1696 }
1703 1697
1704 kfree(entity->controls); 1698 kfree(entity->controls);
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index 39e9e36e883..7d67d95de83 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -236,14 +236,15 @@ struct uvc_control_mapping {
236 236
237struct uvc_control { 237struct uvc_control {
238 struct uvc_entity *entity; 238 struct uvc_entity *entity;
239 struct uvc_control_info *info; 239 struct uvc_control_info info;
240 240
241 __u8 index; /* Used to match the uvc_control entry with a 241 __u8 index; /* Used to match the uvc_control entry with a
242 uvc_control_info. */ 242 uvc_control_info. */
243 __u8 dirty : 1, 243 __u8 dirty:1,
244 loaded : 1, 244 loaded:1,
245 modified : 1, 245 modified:1,
246 cached : 1; 246 cached:1,
247 initialized:1;
247 248
248 __u8 *uvc_data; 249 __u8 *uvc_data;
249}; 250};